У меня есть массив объектов Ruby, как изменить этот массив на несколько массивов на основе свойств этих объектов? - PullRequest
3 голосов
/ 02 февраля 2012

Каков наилучший способ преобразования большого массива в несколько вложенных массивов на основе свойств объектов в исходном массиве?Например, у меня есть массив объектов (все объекты имеют одинаковые свойства):

array = [
    {:name => "Jim", :amount => "20"},
    {:name => "Jim", :amount => "40"},
    {:name => "Jim", :amount => "30"},
    {:name => "Eddie", :amount => "7"},
    {:name => "Eddie", :amount => "12"},
    {:name => "Pony", :amount => "330"},
    {:name => "Pony", :amount => "220"},
    {:name => "Pony", :amount => "50"}
]

Обратите внимание, что все объекты с одинаковыми свойствами name являются последовательными в массиве.Теперь я хочу сгруппировать объекты в подмассивы на основе свойства name.Что мне нужно:

result = [
    [
        {:name => "Jim", :amount => "20"},
        {:name => "Jim", :amount => "40"},
        {:name => "Jim", :amount => "30"}
    ],
    [
        {:name => "Eddie", :amount => "7"},
        {:name => "Eddie", :amount => "12"}
    ],
    [
        {:name => "Pony", :amount => "330"},
        {:name => "Pony", :amount => "220"},
        {:name => "Pony", :amount => "50"}
    ]
]

Какой лучший способ сделать это?Спасибо.

Ответы [ 2 ]

9 голосов
/ 02 февраля 2012

Используйте group_by для подъема тяжестей, а затем map, чтобы вытащить то, что вы хотите:

result = array.group_by { |h| h[:name] }.map { |k, v| v }

Например:

>> results = array.group_by { |h| h[:name] }.map { |k, v| v }
>> pp results
[[{:name=>"Jim", :amount=>"20"},
  {:name=>"Jim", :amount=>"40"},
  {:name=>"Jim", :amount=>"30"}],
 [{:name=>"Eddie", :amount=>"7"},
  {:name=>"Eddie", :amount=>"12"}],
 [{:name=>"Pony", :amount=>"330"},
  {:name=>"Pony", :amount=>"220"},
  {:name=>"Pony", :amount=>"50"}]]

Вы также можете пропустить map и перейти прямо к Hash#values:

result = array.group_by { |h| h[:name] }.values

Спасибо за KandadaBoggu за указаниеэто упущение.

2 голосов
/ 02 февраля 2012

Если хэши с одинаковым значением :name всегда являются последовательными элементами, вы можете сделать это следующим образом:

result = array.each_with_object([]) do |e, memo|
  if memo.last && memo.last.last[:name] == e[:name]
    memo.last << e
  else
    memo << [e] 
  end 
end

или вы можете использовать Enumerable#chunk (опять жеучтите, что элементы с одинаковым значением :name являются последовательными):

result = array.chunk{ |e| e[:name] }.map(&:last)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...