给定一个散列数组,我想创建一个返回散列的方法,其中键是数组中散列的唯一值。
例如,我想
[
{foo: 'bar', baz: 'bang'},
{foo: 'rab', baz: 'bang'},
{foo: 'bizz', baz: 'buzz'}
]
并返回
{
foo: ['bar', 'rab', 'bizz'],
baz: ['bang', 'buzz']
}
我目前正在使用以下方式完成此任务:
def my_fantastic_method(data)
response_data = { foo: [], baz: []}
data.each { |data|
data.attributes.each { |key, value|
response_data[key.to_sym] << value
}
}
response_data.each { |key, value| response_data[key] = response_data[key].uniq }
response_data
end
有更优雅的方式吗?谢谢!
答案 0 :(得分:6)
你目前的方法已经相当不错了;我没有看到很多的改进空间。我会这样写:
def my_fantastic_method(data_list)
data_list.each_with_object(Hash.new { |h, k| h[k] = Set.new }) do |data, result|
data.attributes.each do |key, value|
result[key.to_sym] << value
end
end
end
foo: [], bar: []
。each_with_object
,我已经消除了声明局部变量并在最后显式返回它的需要。Set
,无需在最终结果上调用uniq
。这需要更少的代码,并且性能更高。但是,如果您确实希望最终结果是Array
s而不是Set
s的映射,那么您需要在方法末尾的每个值上调用to_a
。 data_list
和data
使用了不同的变量名称。无论你喜欢什么,都要调用它们,但它通常被视为bad practice以遮蔽外部变量。答案 1 :(得分:2)
这里有几个单行。 (我很确定@eiko很滑稽,但我证明他是正确的)
这个很好读,很容易理解(警告:transform_values
需要Ruby 2.4+):
array.flat_map(&:entries).group_by(&:first).transform_values{|v| v.map(&:last).uniq}
这是另一个,使用merge
的块形式指定备用合并方法,在这种情况下将值组合成uniq数组:
array.reduce{|h, el| h.merge(el){|k, old, new| ([old]+[new]).flatten.uniq}}
答案 2 :(得分:1)
你已经有了一个很好的答案,但我感觉很高兴,所以这里有一个较短的答案:
{{1}}
答案 3 :(得分:1)
试试这个:
array.flat_map(&:entries)
.group_by(&:first)
.map{|k,v| {k => v.map(&:last)} }
OR
a.inject({}) {|old_h, new_h|
new_h.each_pair {|k, v|
old_h.key?(k) ? old_h[k] << v : old_h[k]=[v]};
old_h}
答案 4 :(得分:0)
如果在示例中,所有哈希都具有相同的键,则可以执行以下操作:
arr = [{ foo: 'bar', baz: 'bang' },
{ foo: 'rab', baz: 'bang' },
{ foo: 'bizz', baz: 'buzz' }]
keys = arr.first.keys
keys.zip(arr.map { |h| h.values_at(*keys) }.transpose.map(&:uniq)).to_h
#=> {:foo=>["bar", "rab", "bizz"], :baz=>["bang", "buzz"]}
步骤如下。
keys = arr.first.keys
#=> [:foo, :baz]
a = arr.map { |h| h.values_at(*keys) }
#=> [["bar", "bang"], ["rab", "bang"], ["bizz", "buzz"]]
b = a.transpose
#=> [["bar", "rab", "bizz"], ["bang", "bang", "buzz"]]
c = b.map(&:uniq)
#=> [["bar", "rab", "bizz"], ["bang", "buzz"]]
d = c.to_h
#=> <array of hashes shown above>