如何创建两个哈希的交集?

时间:2013-07-12 06:50:01

标签: ruby

我有两个哈希:

hash1 = {1 => "a" , 2 => "b" , 3 => "c" , 4 => "d"} 
hash2 = {3 => "hello", 4 => "world" , 5 => "welcome"} 

我需要一个散列,其中包含两个散列中的公共键:

hash3 = {3 => "hello" , 4 => "world"}

没有任何循环可以做到吗?

4 个答案:

答案 0 :(得分:16)

hash3 = hash1.keep_if { |k, v| hash2.key? k }

这与问题中的代码效果不同,而是会返回:

hash3 #=> { 3 => "c", 4 => "d" }

哈希的顺序在这里很重要。这些值将始终从#keep_if发送到的哈希值中获取。

hash3 = hash2.keep_if { |k, v| hash1.key? k }
#=> {3 => "hello", 4 => "world"}

答案 1 :(得分:13)

我会这样做:

hash1 = {1 => "a" , 2 => "b" , 3 => "c" , 4 => "d"} 
hash2 = {3 => "hello", 4 => "world" , 5 => "welcome"} 

Hash[(hash1.keys & hash2.keys).zip(hash2.values_at(*(hash1.keys & hash2.keys)))]
=> {3=>"hello", 4=>"world"}

可以减少一点:

keys = (hash1.keys & hash2.keys)
Hash[keys.zip(hash2.values_at(*keys))]

诀窍在于Array的&方法。文档说:

  

Set Intersection - 返回一个新数组,其中包含两个数组共有的元素,不包括任何重复项。订单将从原始数组中保留。


以下是一些基准测试,以显示最有效的方法:

require 'benchmark'

HASH1 = {1 => "a" , 2 => "b" , 3 => "c" , 4 => "d"} 
HASH2 = {3 => "hello", 4 => "world" , 5 => "welcome"} 

def tinman
  keys = (HASH1.keys & HASH2.keys)
  Hash[keys.zip(HASH2.values_at(*keys))]
end

def santhosh
  HASH2.select {|key, value| HASH1.has_key? key }
end
def santhosh_2
  HASH2.select {|key, value| HASH1[key] }
end

def priti
  HASH2.select{|k,v| HASH1.assoc(k) }
end

def koraktor
  HASH1.keep_if { |k, v| HASH2.key? k }
end
def koraktor2
  HASH2.keep_if { |k, v| HASH1.key? k }
end

N = 1_000_000
puts RUBY_VERSION
puts "N= #{N}"

puts [:tinman, :santhosh, :santhosh_2, :priti, :koraktor, :koraktor2].map{ |s| "#{s.to_s} = #{send(s)}" }
Benchmark.bm(11) do |x|
  x.report('tinman') { N.times { tinman() }}
  x.report('santhosh_2') { N.times { santhosh_2() }}
  x.report('santhosh') { N.times { santhosh() }}
  x.report('priti') { N.times { priti() }}
  x.report('koraktor') { N.times { koraktor() }}
  x.report('koraktor2') { N.times { koraktor2() }}
end

Ruby 1.9.3-p448:

1.9.3
N= 1000000
tinman = {3=>"hello", 4=>"world"}
santhosh = {3=>"hello", 4=>"world"}
santhosh_2 = {3=>"hello", 4=>"world"}
priti = {3=>"hello", 4=>"world"}
koraktor = {3=>"c", 4=>"d"}
koraktor2 = {3=>"hello", 4=>"world"}
                  user     system      total        real
tinman        2.430000   0.000000   2.430000 (  2.430030)
santhosh_2    1.000000   0.020000   1.020000 (  1.003635)
santhosh      1.090000   0.010000   1.100000 (  1.104067)
priti         1.350000   0.000000   1.350000 (  1.352476)
koraktor      0.490000   0.000000   0.490000 (  0.484686)
koraktor2     0.480000   0.000000   0.480000 (  0.483327)

在Ruby 2.0.0-p247下运行:

2.0.0
N= 1000000
tinman = {3=>"hello", 4=>"world"}
santhosh = {3=>"hello", 4=>"world"}
santhosh_2 = {3=>"hello", 4=>"world"}
priti = {3=>"hello", 4=>"world"}
koraktor = {3=>"c", 4=>"d"}
koraktor2 = {3=>"hello", 4=>"world"}
                  user     system      total        real
tinman        1.890000   0.000000   1.890000 (  1.882352)
santhosh_2    0.710000   0.010000   0.720000 (  0.735830)
santhosh      0.790000   0.020000   0.810000 (  0.807413)
priti         1.030000   0.010000   1.040000 (  1.030018)
koraktor      0.390000   0.000000   0.390000 (  0.389431)
koraktor2     0.390000   0.000000   0.390000 (  0.389072)

Koraktor的原始代码不起作用,但是他用第二次代码传递很好地转换了它,然后以最快的速度走开了。我添加了santhosh_2方法,以了解删除key?会产生什么影响。它加快了常规程度,但还不足以赶上Koraktor的。


仅出于文档目的,我调整了Koraktor的第二个代码,以便删除key?方法,并从中节省了更多时间。这是添加的方法和新输出:

def koraktor3
  HASH2.keep_if { |k, v| HASH1[k] }
end

1.9.3
N= 1000000
tinman = {3=>"hello", 4=>"world"}
santhosh = {3=>"hello", 4=>"world"}
santhosh_2 = {3=>"hello", 4=>"world"}
priti = {3=>"hello", 4=>"world"}
koraktor = {3=>"c", 4=>"d"}
koraktor2 = {3=>"hello", 4=>"world"}
koraktor3 = {3=>"hello", 4=>"world"}
                  user     system      total        real
tinman        2.380000   0.000000   2.380000 (  2.382392)
santhosh_2    0.970000   0.020000   0.990000 (  0.976672)
santhosh      1.070000   0.010000   1.080000 (  1.078397)
priti         1.320000   0.000000   1.320000 (  1.318652)
koraktor      0.480000   0.000000   0.480000 (  0.488613)
koraktor2     0.490000   0.000000   0.490000 (  0.490099)
koraktor3     0.390000   0.000000   0.390000 (  0.389386)

2.0.0
N= 1000000
tinman = {3=>"hello", 4=>"world"}
santhosh = {3=>"hello", 4=>"world"}
santhosh_2 = {3=>"hello", 4=>"world"}
priti = {3=>"hello", 4=>"world"}
koraktor = {3=>"c", 4=>"d"}
koraktor2 = {3=>"hello", 4=>"world"}
koraktor3 = {3=>"hello", 4=>"world"}
                  user     system      total        real
tinman        1.840000   0.000000   1.840000 (  1.832491)
santhosh_2    0.720000   0.010000   0.730000 (  0.737737)
santhosh      0.780000   0.020000   0.800000 (  0.801619)
priti         1.040000   0.010000   1.050000 (  1.044588)
koraktor      0.390000   0.000000   0.390000 (  0.387265)
koraktor2     0.390000   0.000000   0.390000 (  0.388648)
koraktor3     0.320000   0.000000   0.320000 (  0.327859)

答案 2 :(得分:10)

hash2.select {|key, value| hash1.has_key? key }
# => {3=>"hello", 4=>"world"}

答案 3 :(得分:3)

Ruby 2.5添加了Hash#slice,它允许使用紧凑的代码,如:

hash3 = hash1.slice(*hash2.keys)

在较旧的rubies中,这可以在使用活动支持的散列扩展的rails或项目中实现。