2014-11-03 5 views
0

У меня есть массив хэшей (# 1), который выглядит следующим образом:Рубин массив хэшей значений в строку

data = [{"username"=>"Luck", "mail"=>"[email protected]", "active"=>0}] 

, что я пытаюсь сравнить со следующими массив хэшей (# 2):

test = [{"username"=>"Luck", "mail"=>"[email protected]", "active"=>"0"}] 

где # 1 я получил из базы данных по mysql2 (что на самом деле находится в базе данных) и # 2 от моего огурца сценария (что я минимально ожидать ВЗ быть там).

По определению # 2 должен быть подмножеством # 1, так что я следовать с этим кодом:

data = data.to_set 
test = test.to_set 
assert test.subset?(data) 

Проблема заключается в массиве данных значение active не является строкой. В случае data это Fixnum, а в случае test - String.

Мне нужно решение, которое будет работать даже для более чем одного хэша в массиве. (В качестве базы данных может вернуть более одной строки результатов) Вот почему я конвертировать наборы и использовать subset?

Из других вопросов, которые я получил:

data.each do |obj| 
    obj.map do |k, v| 
    {k => v.to_s} 
    end 
end 

Однако это не работает для меня. Есть идеи?

Предположения вы можете сделать:

  • Все ключи в data всегда будет Strings.
  • Все ключи в test всегда будут строками. И всегда быть идентичным data.
  • Все значения в test всегда будут строками.
+0

что тип, если не строка? Можете ли вы обновить свой пример с типом данных, который он показывает. Также ваша цель - сказать данные == test? Откуда возникает подмножество? – Anthony

+0

Исправлен вопрос, чтобы предоставить ответы, на которые вы заходите. Однако для начинающих получить данные == тест будет хорошим. –

+0

'test' - это подматрица' data', если и только если '(test-data) .puty? => true'.Это то, что вы хотите? Обратите внимание, что если 'h' и' g' являются хэшами, 'h == g => true' тогда и только тогда, когда они имеют одинаковые ключи и значения, независимо от порядка клавиш. –

ответ

0

Вот несколько подходов, которые должны это сделать, если я правильно понял вопрос.

# 1: преобразовать хэш-значения в строки

def stringify_hash_values(h) 
    h.each_with_object({}) { |(k,v),h| h[k] = v.to_s } 
end 

def sorta_subset?(data,test) 
    (test.map { |h| stringify_hash_values(data) } - 
    data.map { |h| stringify_hash_values(data) }).empty? 
end 

data = [{"username"=>"Luck", "mail"=>"[email protected]", "active"=>0}] 
test = [{"username"=>"Luck", "mail"=>"[email protected]", "active"=>"0"}] 
sorta_subset?(data,test) #=> true 

# 2 см, если ключи одинаковы и значения преобразуются в строки равны

require 'set' 

def hashes_sorta_equal?(h,g) 
    hk = h.keys 
    (hk.to_set == g.keys.to_set) && 
    (h.values_at(*hk).map(&:to_s) == g.values_at(*hk).map(&:to_s)) 
end 

def sorta_subset?(data,test) 
    test.all? { |h| data.any? { |g| hashes_sorta_equal?(g,h) } } 
end 

sorta_subset?(data,test) #=> true 
0

Не спрашивайте меня, почему это работает, но я нашел решение:

data.map! do |obj| 
    obj.each do |k, v| 
    obj[k] = "#{v}" 
    end 
end 

Я думаю, что это что-то делать с тем, что функции на массивы и хэши изменить сам объект, а не создать измененная копия объекта.

+0

Это работает, потому что вы преобразовываете каждый элемент в строки. В вашем массиве 'data',' active' сопоставляется с числом, в то время как он сопоставляется с строкой в ​​'test'. Это привело к неудаче сравнения. –

+0

Вот что я хотел сделать. Я сделал это, однако я не совсем уверен, как этот сегмент кода выполнил эту работу. –

+1

Да, это преобразует значения в строки, что позволит вам использовать 'data-test', но следить за непреднамеренными побочными эффектами. Если, например, вы создаете метод 'sorta_subset? (Test, data)', вам нужно признать, что 'test' и' data' будут изменены в вызывающем методе после возврата 'sorta_subset?'. В общем, лучше не изменять («мутировать») эти массивы. Вы также не можете изменить значения в массивах 'dup'ed. См. № 1 в моем решении для способа сделать это без изменения 'data' или' test'. –