收集具有相同值的哈希条目
Collecting hash entries with identical values
我有一个如下所示的数组
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 => 'soft'}]},
{:identifier => '1', :groupinfo => [
{:color => 'green', :texture => 'hard'}]},
{{:identifier => '2', :groupinfo =>
[{:color => 'red', :texture => 'spiky'}]}
我想将具有相同 :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#merge
和 Hash#inject
在这里很有用,但我不确定如何实现它们。
我正在从一个看起来像
的数组中生成 unorganized_array
original_array = [['blue', 'soft', '1', 'irrelevant'], ['green','hard','1','irrelevant1'],
['red','spiky','2','irrelevant2']]
也许有比从 original_array -> unorganized_array -> organized_array?
更好的方法
到目前为止,我一直在尝试使用带有 for 循环的#map 和#each 将它们组合在一起,即
unorganized_array = original_array.map! do |first, second, third, fourth|
{:identifier => third, :groupinfo => [{:color => first, :texture => second}]}
end
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" } ]
目前,您正在生成一个双键哈希数组,其中第二个包含一个属性数组。为什么不使用 "identifier" 作为 key
来代替 Hash
?毕竟,这正是关键所在。
这看起来更干净:
{"1"=>[{:color=>"blue", :texture=>"soft"},
{:color=>"green", :texture=>"hard"}],
"2"=>[{:color=>"red", :texture=>"spiky"}]}
这是一种生成方法:
my_hash = original_array.reduce({}) do |r,s|
r.merge( s[2] => (r[s[2]] || []) + [{color: s[0], texture: s[1]}] )
end
对于@the Tin Man 的观点,理解 Ruby 的 Enumerable
class 比发现我们可以提供的任何特定解决方案更有价值 objective。
使用你的哈希
这是一种遍历所有项目的方法。
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
输出:
Identifier #1 has 2 items
Item #1 is blue and soft
Item #2 is green and hard
Identifier #2 has 1 items
Item #1 is red and spiky
我认为这不是最好的方法,但我建议这样做:
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 - 在预期的散列中收集您的 grouped_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"}]}]
arr =
[{:identifier => '1', :groupinfo => [{:color => 'blue, :texture => 'soft}]},
{:identifier => '1', :groupinfo => [{:color => 'green', :texture => 'hard'}]},
{:identifier => '2', :groupinfo => [{:color => 'red', :texture => 'spiky'}]}]
有几种方法可以通过构建哈希来实现。
使用 Hash::new 的形式,当散列 h
没有键 k
时,使用默认值确定 h[k]
。
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"}]}]
k
、o
、n
、
三个块变量的含义请查阅文档
我有一个如下所示的数组
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 => 'soft'}]}, {:identifier => '1', :groupinfo => [ {:color => 'green', :texture => 'hard'}]}, {{:identifier => '2', :groupinfo => [{:color => 'red', :texture => 'spiky'}]}
我想将具有相同 :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#merge
和 Hash#inject
在这里很有用,但我不确定如何实现它们。
我正在从一个看起来像
的数组中生成 unorganized_arrayoriginal_array = [['blue', 'soft', '1', 'irrelevant'], ['green','hard','1','irrelevant1'],
['red','spiky','2','irrelevant2']]
也许有比从 original_array -> unorganized_array -> organized_array?
更好的方法到目前为止,我一直在尝试使用带有 for 循环的#map 和#each 将它们组合在一起,即
unorganized_array = original_array.map! do |first, second, third, fourth|
{:identifier => third, :groupinfo => [{:color => first, :texture => second}]}
end
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" } ]
目前,您正在生成一个双键哈希数组,其中第二个包含一个属性数组。为什么不使用 "identifier" 作为 key
来代替 Hash
?毕竟,这正是关键所在。
这看起来更干净:
{"1"=>[{:color=>"blue", :texture=>"soft"},
{:color=>"green", :texture=>"hard"}],
"2"=>[{:color=>"red", :texture=>"spiky"}]}
这是一种生成方法:
my_hash = original_array.reduce({}) do |r,s|
r.merge( s[2] => (r[s[2]] || []) + [{color: s[0], texture: s[1]}] )
end
对于@the Tin Man 的观点,理解 Ruby 的 Enumerable
class 比发现我们可以提供的任何特定解决方案更有价值 objective。
使用你的哈希
这是一种遍历所有项目的方法。
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
输出:
Identifier #1 has 2 items
Item #1 is blue and soft
Item #2 is green and hard
Identifier #2 has 1 items
Item #1 is red and spiky
我认为这不是最好的方法,但我建议这样做:
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 - 在预期的散列中收集您的 grouped_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"}]}]
arr =
[{:identifier => '1', :groupinfo => [{:color => 'blue, :texture => 'soft}]},
{:identifier => '1', :groupinfo => [{:color => 'green', :texture => 'hard'}]},
{:identifier => '2', :groupinfo => [{:color => 'red', :texture => 'spiky'}]}]
有几种方法可以通过构建哈希来实现。
使用 Hash::new 的形式,当散列 h
没有键 k
时,使用默认值确定 h[k]
。
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"}]}]
k
、o
、n
、