我有一个哈希数组,我想要它的唯一值。致电Array.uniq
并不能满足我的期望。
a = [{:a => 1},{:a => 2}, {:a => 1}]
a.uniq # => [{:a => 1}, {:a => 2}, {:a => 1}]
我的预期:
[{:a => 1}, {:a => 2}]
在网上搜索时,我没有想出一个我满意的解决方案。人们建议重新定义Hash.eql?
和Hash.hash
,因为这是Array.uniq
正在查询的内容。
编辑: 在现实世界中遇到这种情况时,哈希稍微复杂一些。它们是解析的JSON的结果,它具有多个字段,其中一些值也是哈希值。我有一系列的结果,我想过滤掉唯一的值。
我不喜欢重新定义的Hash.eql?
和Hash.hash
解决方案,因为我要么必须全局重新定义Hash
,要么为我的数组中的每个条目重新定义它。更改每个条目的Hash
的定义会很麻烦,尤其是因为每个条目中可能存在嵌套的哈希值。
在全球范围内更改Hash
有一定的潜力,特别是如果它是暂时完成的话。我想构建另一个类或辅助函数来包装保存旧的定义并恢复它们,但我认为这会增加实际需要的复杂性。
使用inject
似乎是重新定义Hash
的好方法。
答案 0 :(得分:27)
通过致电inject
a = [{:a => 1},{:a => 2}, {:a => 1}]
a.inject([]) { |result,h| result << h unless result.include?(h); result }
这将返回:
[{:a=>1}, {:a=>2}]
答案 1 :(得分:17)
Ruby 1.8.7+将返回您所期望的内容:
[{:a=>1}, {:a=>2}, {:a=>1}].uniq
#=> [{:a=>1}, {:a=>2}]
答案 2 :(得分:5)
我遇到了类似的情况,但哈希有钥匙。我使用了排序方法。
我的意思是:
你有一个数组:[{:x=>1},{:x=>2},{:x=>3},{:x=>2},{:x=>1}]
你对它进行排序(#sort_by {|t| t[:x]}
)并得到它:
[{:x=>1}, {:x=>1}, {:x=>2}, {:x=>2}, {:x=>3}]
现在是Aaaron Hinni的一个修改版本的回答:
your_array.inject([]) do |result,item|
result << item if !result.last||result.last[:x]!=item[:x]
result
end
我也试过了:
test.inject([]) {|r,h| r<<h unless r.find {|t| t[:x]==h[:x]}; r}.sort_by {|t| t[:x]}
但它很慢。这是我的基准:
test=[]
1000.times {test<<{:x=>rand}}
Benchmark.bmbm do |bm|
bm.report("sorting: ") do
test.sort_by {|t| t[:x]}.inject([]) {|r,h| r<<h if !r.last||r.last[:x]!=h[:x]; r}
end
bm.report("inject: ") {test.inject([]) {|r,h| r<<h unless r.find {|t| t[:x]==h[:x]}; r}.sort_by {|t| t[:x]} }
end
结果:
Rehearsal ---------------------------------------------
sorting: 0.010000 0.000000 0.010000 ( 0.005633)
inject: 0.470000 0.140000 0.610000 ( 0.621973)
------------------------------------ total: 0.620000sec
user system total real
sorting: 0.010000 0.000000 0.010000 ( 0.003839)
inject: 0.480000 0.130000 0.610000 ( 0.612438)
答案 3 :(得分:3)
假设您的哈希值始终是单键值对,则可以使用:
a.map {|h| h.to_a[0]}.uniq.map {|k,v| {k => v}}
Hash.to_a创建一个键值数组数组,因此第一个映射可以获得:
[[:a, 1], [:a, 2], [:a, 1]]
uniq on Arrays做你想要的,给你:
[[:a, 1], [:a, 2]]
然后第二张地图再次将它们作为哈希重新组合在一起。
答案 4 :(得分:1)
您可以使用(在ruby 1.9.3中测试),
[{a: 1},{a: 2},{a:1}].uniq => [{a:1},{a: 2}]
[{a: 1,b: 2},{a: 2, b: 2},{a: 1, b: 3}].uniq_by {|v| v[:a]} => [{a: 1,b: 2},{a: 2, b: 2}]
答案 5 :(得分:0)
您给出的答案类似于所讨论的答案here。它会覆盖要在数组中显示的哈希值上的hash
和eql?
方法,然后使uniq
行为正确。
答案 6 :(得分:0)
答案 7 :(得分:0)
数组上的管道方法(自1.8.6起可用)执行set union(返回数组),因此以下是获取任何数组a
的唯一元素的另一种可能方法:
[] | a