2013-07-12 5 views
8

У меня есть два хэшей:Как создать пересечение двух хэшей?

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

мне нужен хэш, который содержит общие ключи в обоих хешей:

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

Можно ли это сделать без какого-либо цикла?

+1

* Без петли * нет. Почему вы не хотите использовать циклы? – Shoe

+3

Я предполагаю, что он означает «без кодирования цикла сам и использовать какой-то встроенный метод». – Koraktor

+2

Вам небезразличны значения или просто ключи являются пересечением данных хэшей? –

ответ

12
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

дает hash3 = {3 => "c", 4 => "d"}, но user require- hash3 = {3 => "hello", 4 => "world"} –

+0

См. Мой отредактированный ответ. – Koraktor

+0

да теперь он работает –

9

Я бы с этим:

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))] 

Хитрость заключается в & методе массива. В документации указано:

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 

рубин 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) 

Запуск под Рубине 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, чтобы удалить метод 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) 
+0

Thanx для ур ответ, он работает ........ – user2575339

+0

Спасибо. Посмотрите на бенчмарк. Код пользователя2564200 с незначительной настройкой является самым быстрым. –

+0

Коратор является самым быстрым. Вы изменили свой код после того, как я написал тест, поэтому, в то время как ваш теперь отражает использование 'Hash []', он изначально использовал 'assoc', о чем свидетельствует история изменений. –

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

Это самое элегантное решение, которое я когда-либо видел на этом сайте. – Fuser97381

Смежные вопросы