I want to get the union/intersect/difference from two arrays of hashes for example:
我想从两个哈希数组得到union / intersect / difference,例如:
array1 = [{:name =>'Guy1', :age => 45},{:name =>'Guy2', :age => 45}]
array2 = [{:name =>'Guy1', :age => 45},{:name =>'Guy3', :age => 45}]
...
p array1 - array2
=> [{:name=>"Guy2", :age=>45}]
p array2 - array1
=> [{:name=>"Guy3", :age=>45}]
p array1 | array2
=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}, {:name=>"Guy3", :age=>45}]
however when I want to only compare based on the names and ignore the ages without needing to remove them from the hashes for example:
但是,当我只想根据名称进行比较并忽略年龄而不需要从哈希中删除它们时,例如:
array1 = [{:name =>'Guy1', :age => 45},{:name =>'Guy2', :age => 45}]
array2 = [{:name =>'Guy1', :age => 46},{:name =>'Guy3', :age => 45}]
In this case i'm not getting the results that I want b/c the ages are different.
在这种情况下,我没有得到我想要的结果b / c年龄不同。
array1 - array2
=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}]
array2 - array1
=> [{:name=>"Guy1", :age=>46}, {:name=>"Guy3", :age=>45}]
array1 | array2
=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}, {:name=>"Guy1", :age=>46}, {:name=>"Guy3", :age=>45}]
Is there a way to get the union/intersect/difference and ignore the age key?
有没有办法获得联合/交叉/差异并忽略年龄密钥?
edit: for a better example:
编辑:更好的例子:
array1 = [{:name =>'Guy1', :age => 45},{:name =>'Guy2', :age => 45}]
array2 = [{:name =>'Guy1'},{:name =>'Guy3'}]
p array1 - array2
p array2 - array1
p array1 | array2
p array1 & array2
Thanks in advance for the help!
先谢谢您的帮助!
3 个解决方案
#1
5
Here's a quick and dirty way of getting the union:
这是获得联盟的快速而肮脏的方式:
(array1 + array2).uniq{|a| a[:name]}
However, I would recommend creating your own subclass of Hash
so you can safely override eql?
as Cary Swoveland points out is what the set-like operators rely on. Note that you also need to limit the hash
method to only provide the hashing function on the name field.
但是,我建议您创建自己的Hash子类,以便安全地覆盖eql?正如Cary Swoveland所指出的那样是集合式运营商所依赖的。请注意,您还需要将哈希方法限制为仅在名称字段上提供哈希函数。
class Guy < Hash
def eql?(other_hash)
self[:name] == other_hash[:name]
end
def hash
self[:name].hash
end
end
Then these Guy
objects will work in all of the set operations:
然后这些Guy对象将在所有set操作中起作用:
array1 = [ Guy[name:'Guy1', age: 45], Guy[name:'Guy2', age: 45] ]
array2 = [ Guy[name:'Guy1', age: 46], Guy[name:'Guy3', age: 45] ]
array1 - array2
#=> [{:name=>"Guy2", :age=>45}]
array2 - array1
#=> [{:name=>"Guy3", :age=>45}]
array1 | array2
#=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}, {:name=>"Guy3", :age=>
45}]
array1 & array2
#=> [{:name=>"Guy1", :age=>45}]
#2
0
For the difference:
差异:
diff_arr = array1.map{|a| a[:name]} - array2.map{|a| a[:name]}
diff_arr.map{|a| array1.map{|s| s if s[:name] == a }}.flatten.compact
Intersection
intersec_arr = array1.map{|a| a[:name]} & array2.map{|a| a[:name]}
intersec_ar.map{|a| array1.map{|s| s if s[:name] == a }}.flatten.compact
#3
0
All three class Array
methods referenced use Hash#eql? to compare two elements that are both hashes. (Hash#eql?
checks to see if the hashcodes for the two hashes are equals.) Therefore, we need only (temporarily) redefine Hash#eql?
.
引用的所有三个类Array方法都使用Hash #eql?比较两个哈希的两个元素。 (Hash #eql?检查两个哈希的哈希码是否相等。)因此,我们只需要(暂时)重新定义哈希#eql?。
array1 = [{:name =>'Guy1', :age => 45}, {:name =>'Guy2', :age => 45}]
array2 = [{:name =>'Guy1'}, {:name =>'Guy3'}]
class Hash
alias old_eql? eql?
def eql?(h) self[:name] == h[:name] end
end
array1 - array2
#=> [{:name=>"Guy2", :age=>45}]
array2 - array1
#=> [{:name=>"Guy3"}]
array1 | array2
#=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}, {:name=>"Guy3"}]
array1 & array2
#=> [{:name=>"Guy1", :age=>45}]
class Hash
alias eql? old_eql? # Restore eql?
undef_method :old_eql?
end
Note that this is one of those few situations where self
must be explicit. If we wrote:
请注意,这是必须明确自我的少数情况之一。如果我们写道:
[:name] == h[:name]
instead of:
self[:name] == h[:name]
Ruby would assume that we are comparing the array [:name]
with h[:name]
.
Ruby会假设我们正在将数组[:name]与h [:name]进行比较。
#1
5
Here's a quick and dirty way of getting the union:
这是获得联盟的快速而肮脏的方式:
(array1 + array2).uniq{|a| a[:name]}
However, I would recommend creating your own subclass of Hash
so you can safely override eql?
as Cary Swoveland points out is what the set-like operators rely on. Note that you also need to limit the hash
method to only provide the hashing function on the name field.
但是,我建议您创建自己的Hash子类,以便安全地覆盖eql?正如Cary Swoveland所指出的那样是集合式运营商所依赖的。请注意,您还需要将哈希方法限制为仅在名称字段上提供哈希函数。
class Guy < Hash
def eql?(other_hash)
self[:name] == other_hash[:name]
end
def hash
self[:name].hash
end
end
Then these Guy
objects will work in all of the set operations:
然后这些Guy对象将在所有set操作中起作用:
array1 = [ Guy[name:'Guy1', age: 45], Guy[name:'Guy2', age: 45] ]
array2 = [ Guy[name:'Guy1', age: 46], Guy[name:'Guy3', age: 45] ]
array1 - array2
#=> [{:name=>"Guy2", :age=>45}]
array2 - array1
#=> [{:name=>"Guy3", :age=>45}]
array1 | array2
#=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}, {:name=>"Guy3", :age=>
45}]
array1 & array2
#=> [{:name=>"Guy1", :age=>45}]
#2
0
For the difference:
差异:
diff_arr = array1.map{|a| a[:name]} - array2.map{|a| a[:name]}
diff_arr.map{|a| array1.map{|s| s if s[:name] == a }}.flatten.compact
Intersection
intersec_arr = array1.map{|a| a[:name]} & array2.map{|a| a[:name]}
intersec_ar.map{|a| array1.map{|s| s if s[:name] == a }}.flatten.compact
#3
0
All three class Array
methods referenced use Hash#eql? to compare two elements that are both hashes. (Hash#eql?
checks to see if the hashcodes for the two hashes are equals.) Therefore, we need only (temporarily) redefine Hash#eql?
.
引用的所有三个类Array方法都使用Hash #eql?比较两个哈希的两个元素。 (Hash #eql?检查两个哈希的哈希码是否相等。)因此,我们只需要(暂时)重新定义哈希#eql?。
array1 = [{:name =>'Guy1', :age => 45}, {:name =>'Guy2', :age => 45}]
array2 = [{:name =>'Guy1'}, {:name =>'Guy3'}]
class Hash
alias old_eql? eql?
def eql?(h) self[:name] == h[:name] end
end
array1 - array2
#=> [{:name=>"Guy2", :age=>45}]
array2 - array1
#=> [{:name=>"Guy3"}]
array1 | array2
#=> [{:name=>"Guy1", :age=>45}, {:name=>"Guy2", :age=>45}, {:name=>"Guy3"}]
array1 & array2
#=> [{:name=>"Guy1", :age=>45}]
class Hash
alias eql? old_eql? # Restore eql?
undef_method :old_eql?
end
Note that this is one of those few situations where self
must be explicit. If we wrote:
请注意,这是必须明确自我的少数情况之一。如果我们写道:
[:name] == h[:name]
instead of:
self[:name] == h[:name]
Ruby would assume that we are comparing the array [:name]
with h[:name]
.
Ruby会假设我们正在将数组[:name]与h [:name]进行比较。