Учитывая, что у меня есть массив с двумя атрибутами: 'n_parents' и 'class', который выглядит так:

my_arr = [{n_parents: 10, class: 'right'}, {n_parents: 10, class: 'right'}, {n_parents: 5, class: 'left'}, {n_parents: 2, class: 'center'}, {n_parents: 2, class: 'center'}, {n_parents: 2, class: 'center'}]

Я хотел бы получить массив с объектами, которые имеют большую часть этих двух атрибутов. Итак, в предыдущем примере:

result = [{n_parents: 2, class: 'center'}, {n_parents: 2, class: 'center'}, {n_parents: 2, class: 'center'}]

Потому что есть три объекта, которые совместно используют n_parents = 2 и class = 'center'.

Пока я знаю, как сгруппировать по двум атрибутам, но после этого я не уверен, как получить набор, в котором есть больше элементов.

Прямо сейчас у меня есть:

my_arr.group_by { |x| [x[:n_parents], x[:class]] }
0
StarTrek18 26 Мар 2014 в 22:40

4 ответа

Лучший ответ

Это должно сработать для вас. Он группирует хэши по самому хешу, а затем получает самую большую группу по счетчику массива.

 my_arr = [{n_parents: 10, class: 'right'}, {n_parents: 10, class: 'right'}, {n_parents: 5, class: 'left'}, {n_parents: 2, class: 'center'}, {n_parents: 2, class: 'center'}, {n_parents: 2, class: 'center'}]
 my_arr.group_by { |h| h }.max_by { |h,v| v.count }.last
 #=>[{:n_parents=>2, :class=>"center"}, {:n_parents=>2, :class=>"center"}, {:n_parents=>2, :class=>"center"}]
2
Arup Rakshit 26 Мар 2014 в 22:57
Вы пропустили #last в конце. Итак, я думал, без метода, как вы получили результат .. ;)
 – 
Arup Rakshit
26 Мар 2014 в 22:58
1
Я заметил и добавил это, почему вам нужно было добавить пробелы? ясность?
 – 
engineersmnky
26 Мар 2014 в 22:59
Конечно, любителям руби нравится так писать. См. здесь..
 – 
Arup Rakshit
26 Мар 2014 в 23:00
1
Хорошо, мне просто интересно, так как это, очевидно, работает в любом случае. Я также большой любитель рубинов, и мне больше всего нравится то, что синтаксис почти не знает пробелов. (Основная причина, по которой я не такой большой поклонник Python)
 – 
engineersmnky
26 Мар 2014 в 23:05

Что-то вроде ниже:

my_arr.group_by(&:values).max_by { |_,v| v.size }.last
# => [{:n_parents=>2, :class=>"center"},
#     {:n_parents=>2, :class=>"center"},
#     {:n_parents=>2, :class=>"center"}]
0
Arup Rakshit 26 Мар 2014 в 22:54

Я использую код, используемый OP, и расширяю его, чтобы получить желаемый результат: -

my_arr.group_by { |x| [x[:n_parents], x[:class]] }.max_by{|k,v| v.size}.last

Выход

#=> [{:n_parents=>2, :class=>"center"}, {:n_parents=>2, :class=>"center"}, {:n_parents=>2, :class=>"center"}]
0
Alok Anand 26 Мар 2014 в 23:13

Это четвертый ответ, который будет опубликован. Все три предыдущих ответа использовали group_by / max_by / last. Конечно, это может быть лучший подход, но самый ли он интересный, самый веселый? Вот еще пара способов добиться желаемого результата. Когда

my_arr = [{n_parents: 10, class: 'right' }, {n_parents: 10, class: 'right' },
          {n_parents:  5, class: 'left'  }, {n_parents:  2, class: 'center'},
          {n_parents:  2, class: 'center'}, {n_parents:  2, class: 'center'}]

Желаемый результат:

  #=> [{:n_parents=>2, :class=>"center"},
  #    {:n_parents=>2, :class=>"center"},
  #    {:n_parents=>2, :class=>"center"}]

< Сильный > # 1

# Create a hash `g` whose keys are the elements of `my_arr` (hashes)
# and whose values are counts for the elements of `my_arr`.
# `max_by` the values (counts) and construct the array. 

el, nbr = my_arr.each_with_object({}) { |h,g| g[h] = (g[h] ||= 0) + 1 }
                .max_by { |_,v| v } 
arr = [el]*nbr

# 2

# Sequentially delete the elements equal to the first element of `arr`,
# each time calculating the number of elements deleted, by determining
# `arr.size` before and after the deletion. Compare that number with the
# largest number deleted so far to find the element with the maximum
# number of instances in `arr`, then construct the array. 

arr = my_arr.map(&:dup)
most_plentiful = { nbr_copies: 0, element: [] }
until arr.empty? do
  sz = arr.size
  element = arr.delete(arr.first)
  if sz - arr.size > most_plentiful[:nbr_copies]
    most_plentiful = { nbr_copies: sz - arr.size, element: element }
  end
end
arr = [most_plentiful[:element]]* most_plentiful[:nbr_copies]
0
Cary Swoveland 28 Мар 2014 в 00:56
Да, ваш код, безусловно, работает и представляет собой интересный подход, но в то же время в будущем он будет реорганизован, поскольку ему не хватает краткости и удобочитаемости других ответов.
 – 
engineersmnky
29 Мар 2014 в 18:55
@engineersmnky, согласен на 100%. Если бы это было в реальной жизни, я бы использовал group_by/max_by, как и все остальные. Однако я многое узнал о Ruby, пытаясь придумать разные, иногда нетрадиционные, решения SO-вопросов, особенно когда я опаздываю на вечеринку, как здесь. Я публикую эти размышления в надежде, что они могут иметь некоторую образовательную ценность. Попробуй!
 – 
Cary Swoveland
29 Мар 2014 в 20:30