2014-04-17 3 views
11

Как я могу определить, является ли хэш-символ Ruby подмножеством (или включает) другой хеш?Проверка Ruby Hash подмножество?

Например:

hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7} 
hash.include_hash?({})   # true 
hash.include_hash?({f: 6, c: 3}) # true 
hash.include_hash?({f: 6, c: 1}) # false 
+3

Мэтт, ты, кажется, были пожаловал с [смущения богатства] (Http: //dictionary.cambridge. орг/словарь/британец/ан-затруднение-оф князей). (Ссылка для тех, для которых английский является вторым языком.) Получение четырех из четырех качественных ответов на SO довольно редко. –

ответ

9

С Руби 2.3 вы можете также сделать следующее, чтобы проверить, является ли это подмножество

hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7} 
{} <= hash   # true 
{f: 6, c: 3} <= hash # true 
{f: 6, c: 1} <= hash # false 
+0

работает ли это с вложенными хешами? В противном случае это определенно краткий ответ. – nus

+0

@nus это работает с вложенными хешами. Однако вложенный хэш должен быть равен другому, поэтому он не может быть просто подмножеством: '{a: {x: 1, y: 2}} <= {a: {x: 1, y: 2}, b: 3} # true' '{a: {x: 1}} <= {a: {x: 1, y: 2}, b: 3} # false' – Pieter

+0

Также работает наоборот:' хэш > = {f: 6, c: 3} ' –

16

Решение, которое пришло мне в использовании ума Hash#merge метод:

class Hash 
    def include_hash?(hash) 
    merge(hash) == self 
    end 
end 

hash = {a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7} 
hash.include_hash?({}) 
# => true 
hash.include_hash?(f: 6, c:3) 
# => true 
hash.include_hash?(f: 6, c:1) 
# => false 
+0

Мне это нравится, Марек, отчасти потому, что он хорошо читается. –

+2

И для вложенного хэша вы можете использовать 'active_merge' активной поддержки (http://apidock.com/rails/Hash/deep_merge) – Musaffa

+0

Это очень элегантно. Я называю мой «superset?», Хотя и сделал «подмножество?». – nus

7

Вы можете конвертировать хэши в sets и чем выполнить проверку с помощью методов subset? и superset? (или их соответствующие алиасы <= и >=):

require 'set' 

hash.to_set.superset?({}.to_set) 
# => true 

hash.to_set >= {a: 1}.to_set 
# => true 

{a: 2}.to_set <= hash.to_set 
# => false 

Update: эталон предлагаемых решений:

require 'fruity' 
require 'set' 

hash = ('aa'..'zz').zip('aa'..'zz').to_h 
# {"aa"=>"aa", "ab"=>"ab", ... 
find = ('aa'..'zz').zip('aa'..'zz').select { |k, _| k[0] == k[1] }.to_h 
# {"aa"=>"aa", "bb"=>"bb", ... 

compare(
    toro2k:  -> { hash.to_set >= find.to_set }, 
    MarekLipka: -> { hash.merge(find) == hash }, 
    CarySwoveland: -> { (find.to_a - hash.to_a).empty? }, 
    ArupRakshit: -> { arr = hash.to_a; find.all? { |pair| arr.include?(pair) } } 
) 

Результат:

Running each test 2 times. Test will take about 1 second. 
MarekLipka is faster than toro2k by 3x ± 0.1 
toro2k is faster than CarySwoveland by 39.99999999999999% ± 10.0% 
CarySwoveland is faster than ArupRakshit by 1.9x ± 0.1 
+0

это круто :-) –

+0

Спасибо! На основе 'Set # superset?', Я должен вызывать метод 'Hash # superset? 'Вместо' Hash # include_hash? '. – ma11hew28

+0

Наверное, 'superset?' Будет лучшим именем, но я думаю, что это просто вопрос вкуса. – toro2k

6

Вы можете сделать:

def include_hash?(hash,subset_hash) 
    arr = hash.to_a 
    subset_hash.all? { |pair| arr.include?(pair) } 
end 
+0

Может ли кто-нибудь проверить, есть ли 'subset_hash.all? {| пара | arr.include? (pair)} 'также работает или нет ... Я ушел от компьютера, поэтому не смог проверить то же самое. –

+0

Я проверил несколько тестовых примеров и, похоже, работает правильно. – ma11hew28

+0

@MattDiPasquale Спасибо ... Я обновил его сейчас. –

8

разница массив кажется простой:

class Hash 
    def include_hash?(h) 
    (h.to_a - to_a).empty? 
    end 
end 

h = {a: 1, b: 2} 
h.include_hash?({b: 2}) #=> true 
h.include_hash?({b: 3}) #=> false 
+0

Я понимаю '(h.to_a - to_a)' .. Но для лучшей читаемости '(h.to_a - self.to_a)' ... IMO –

+3

@Arup, я почтительно не согласен, хотя я знаю, что ваше мнение разделяют многие другие. Imo, 'self.to_a' предполагает, что здесь требуется' self' (как это было бы, если бы за ним следовал аксессор или 'class'). Я думаю, что всегда лучше избегать использования 'self', когда это не требуется.Если читателя путают 'to_a' без' self', они быстро выяснят это и узнают что-то в сделке. –