Как отобразить уникальные значения из многоуровневого массива в хэш value => array? - PullRequest
2 голосов
/ 09 сентября 2010

У меня есть массив, который выглядит примерно так:

[[100, "one"],
 [101, "one"],
 [102, "one"],
 [103, "two"],
 [104, "three"],
 [105, "three"]]

Я хотел бы создать массив хешей, который выглядит следующим образом

[{"one" => [100,101,102]},
 {"two" => [103]},
 {"three" => [104,105]}]

Числовая частьвсегда будет уникальным, строковая часть будет иметь дубликаты.Каждый раз, когда я думаю об этом, я получаю какую-то длинную функцию, я хотел бы знать «путь рельсов», я уверен, что есть какая-то непонятная функция, которую мне не хватает.

Ответы [ 8 ]

5 голосов
/ 09 сентября 2010

Не помощник по Rails, но обычная идиома Ruby может привести вас туда.Немного

arr.inject({}) { |h,(v,k)| h[k] ||= []; h[k] << v; h }

сделает свое дело.

2 голосов
/ 09 сентября 2010
array = [[100, "one"], [101, "one"], [102, "one"], [103, "two"], [104, "three"], [105, "three"]]
h = Hash.new { |h,k| h[k] = []}
array.each { |a| h[a[1]] << a[0] }
1 голос
/ 09 сентября 2010

Если вам нужен только групповой материал, вы можете использовать функцию Rails group_by:

[[100, "one"],
 [101, "one"],
 [102, "one"], 
 [103, "two"],
 [104, "three"],
 [105, "three"]].group_by { |a| a[1] }

 => #<OrderedHash {"three"=>[[104, "three"], [105, "three"]],
                   "two"=>[[103, "two"]], 
                   "one"=>[[100, "one"], [101, "one"], [102, "one"]]}

Не далеко от того, что вам нужно.Так что, если вы можете использовать его как есть, я думаю, это нормально, но если вам нужен точный формат, который вы сказали.Я думаю, что проще сделать это самому, чем использовать это и конвертировать.

0 голосов
/ 10 сентября 2010

Самый короткий способ получить именно то, что вы просите, и я могу придумать:

a = [[100, "one"],
     [101, "one"],
     [102, "one"], 
     [103, "two"],
     [104, "three"],
     [105, "three"]]

b = a.group_by(&:pop)
#=> {"three"=>[[104], [105]], "two"=>[[103]], "one"=>[[100], [101], [102]]}

, что, вероятно, то, что вы хотите.

обратите внимание, что a получаетразрушенный этим

a
#=> [[100], [101], [102], [103], [104], [105]]

, если вас это беспокоит, вы можете написать

b = a.map(&:dup).group_by &:pop

.

И если вы действительно хотите этот формат, который вы написали, вы можете добавитьдругая карта:

b.map{|h,k| [h => k]}
#=> [{"one" => [100,101,102]}, {"two" => [103]}, {"three" => [104,105]}]

Итак, подведем итог:

[[100, "one"],
 [101, "one"],
 [102, "one"], 
 [103, "two"],
 [104, "three"],
 [105, "three"]].group_by(&:pop).map{ |h,k| [h => k] }
0 голосов
/ 10 сентября 2010

Есть ли конкретная причина, по которой вам нужен этот определенный формат, то есть массив одноэлементных хешей вместо простого стандартного хеша? Потому что в этом случае это будет буквально

arr.group_by(&:last)
0 голосов
/ 09 сентября 2010

Вот одна реализация

your_array.inject(Hash.new{|h,k| h[k] = []}) do |result, (a, b)|
  result[b] << a
  result
end
0 голосов
/ 09 сентября 2010

Как указывает Шингара, это довольно специфично для формата массива (ов).Вы можете делать то, что вам нужно, вот так:

a = [...your data...]
r = a.inject( {} ) do |h, el|
  h[el.last] ||= []
  h[el.last] << el.first
  h
end

Это дает такой результат, как: {'one' => [101, 102], ... }, что лучше, чем ваш запрос для массива хешей с одним ключом, IMO.

0 голосов
/ 09 сентября 2010

На самом деле для этого нет функции. Вам нужно использовать Inject и создать себе хэш.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...