收集具有相同值的哈希条目

时间:2016-06-27 17:58:27

标签: arrays ruby hash uniqueidentifier

我有一个如下所示的数组

unorganized_array = [
  {:identifier => '1', :groupinfo => [{:color => 'blue',  :texture => 'soft'}]},
  {:identifier => '1', :groupinfo => [{:color => 'green', :texture => 'hard'}]},
  {:identifier => '2', :groupinfo => [{:color => 'red',   :texture => 'spiky'}]}]

[{:identifier => ' 1',:groupinfo => [     {:color => ' blue',:texture => '软'}]},     {:identifier => ' 1',:groupinfo => [     {:color => ' green',:texture => '硬盘'}]},     {{:identifier => ' 2',:groupinfo =>     [{:color => ' red',:texture => '高低不平'}]}

我想将具有相同:identifier的所有条目收集到该标识符:groupinfo中。与前一个示例相比,这有一个额外的:identifier => '2'组:

organized_array = [{:identifier => '1', :groupinfo => [
{:color => 'blue', :texture => 'soft'}, 
{:color => 'green', :texture => 'hard'}]},
{:identifier => '2', :groupinfo =>
[{:color => 'red', :texture => 'spiky'},
{:color => 'gray', :texture => 'squishy}]}]

我觉得Hash#mergeHash#inject在这里很有用,但我不确定如何实现它们。

我从一个看起来像

的数组中制作unorganized_array
original_array = [['blue', 'soft', '1', 'irrelevant'], ['green','hard','1','irrelevant1'],
['red','spiky','2','irrelevant2']]

也许有一种比从original_array更好的方法 - > unorganized_array - > organized_array?

到目前为止,我一直在尝试使用#map和#each for for循环将它们组合在一起,即

unorganized_array = original_array.map! do |first, second, third, fourth|
    {:identifier => third, :groupinfo => [{:color => first, :texture => second}]}
end

4 个答案:

答案 0 :(得分:1)

unorganized_array.map(&:dup)
                 .group_by { |e| e.delete(:identifier) }
                 .map { |k, v| [k, v.flat_map { |h| h[:groupinfo] } ] }
                 .map { |k, v| { identifier: k, groupinfo: v } }

上面给出了输入显示:

#⇒ [ { :groupinfo => [ 
#         { :color => "blue", :texture => "soft" },
#         { :color => "green", :texture => "hard" } ],
#      :identifier => "1" },
#    { :groupinfo => [
#         { :color => "red", :texture => "spiky" } ],
#      :identifier => "2" } ]

答案 1 :(得分:1)

目前,您正在生成一个2键哈希数组,其中第二个哈希包含一个属性数组。为什么不使用“标识符”作为key的{​​{1}}?毕竟,这正是关键所在。

这看起来更干净:

Hash

这是产生这种情况的一种方式:

{"1"=>[{:color=>"blue", :texture=>"soft"}, 
       {:color=>"green", :texture=>"hard"}], 
"2"=>[{:color=>"red", :texture=>"spiky"}]}

至于Tin Man的观点,理解Ruby的my_hash = original_array.reduce({}) do |r,s| r.merge( s[2] => (r[s[2]] || []) + [{color: s[0], texture: s[1]}] ) end 类是比发现我们可以提供的任何特定解决方案更有价值的目标。

使用你的哈希

这是迭代所有项目的一种方式。

Enumerable

输出:

my_hash.each do |key,arr| 
  puts "Identifier \##{key} has #{arr.size} items"
  arr.each_with_index do |item,index|
    puts "Item \##{index+1} is #{item[:color]} and #{item[:texture]}"
  end
end

答案 2 :(得分:1)

arr =
  [{:identifier => '1', :groupinfo => [{:color => 'blue,   :texture => 'soft}]},
   {:identifier => '1', :groupinfo => [{:color => 'green', :texture => 'hard'}]},
   {:identifier => '2', :groupinfo => [{:color => 'red',   :texture => 'spiky'}]}]

通过构建哈希,有几种方法可以做到这一点。

当散列h[k]没有密钥h时,使用Hash::new使用默认值来确定k的格式。 < / p>

hash_with_default = Hash.new { |h,k| { identifier: k, groupdata: [] } }

arr.each_with_object(hash_with_default) { |g,h| h[g[:identifier]] =
  { identifier: g[:identifier],
    groupdata:  h[g[:identifier]][:groupdata] << g[:groupinfo].first } }.values
  #=> [{:identifier=>"1", :groupinfo=>[{:color=>"blue", :texture=>"soft"},
  #                                    {:color=>"green", :texture=>"hard"}]},
  #    {:identifier=>"2", :groupinfo=>[{:color=>"red", :texture=>"spiky"}]}] 

使用Hash#update(又名merge!)的形式使用块来确定合并的两个哈希中存在的键的值

arr.each_with_object({}) { |g,h| h.update(g[:identifier] => g) { |k,o,n|
  { identifier: o[:identifier], groupinfo: h[k][:groupinfo] + g[:groupinfo] } } }.values
  #=> [{:identifier=>"1", :groupinfo=>[{:color=>"blue", :texture=>"soft"},
  #                                    {:color=>"green", :texture=>"hard"}]},
  #    {:identifier=>"2", :groupinfo=>[{:color=>"red", :texture=>"spiky"}]}] 

请参阅文档,了解三个区块变量kon的含义。

答案 3 :(得分:0)

我认为这不是最好的方法,但我建议这样做:

1-按标识符对数组进行分组

unorganized_array.group_by{|x| x[:identifier]}
#=>  {"1"=>[{:identifier=>"1", :groupinfo=>[{:color=>"blue", :texture=>"soft"}]},
{:identifier=>"1", :groupinfo=>[{:color=>"green", :texture=>"hard"}]}],
"2"=>[{:identifier=>"2", :groupinfo=>[{:color=>"red", :texture=>"spiky"}]}]}

2 - 在预期的哈希中收集您的groups_array元素并收集组信息值。现在,数组中的每个元素都包含相关项。

group_array.each.collect {|k,g| { :identifier => k, :group_info => g.collect{ |x| x[:groupinfo].last } } }

3-结果是有组织的数组

[{:identifier=>"1", :group_info=>[
 {:color=>"blue", :texture=>"soft"}, 
 {:color=>"green", :texture=>"hard"}
]}, 
{:identifier=>"2", :group_info=>[{:color=>"red", :texture=>"spiky"}]}]