2016-10-06 2 views
0

У меня есть массив ФФ:Рубин коды работает

words = ['demo', 'none', 'tied', 'evil', 'dome', 'mode', 'live', 
      'fowl', 'veil', 'wolf', 'diet', 'vile', 'edit', 'tide', 
      'flow', 'neon'] 

А теперь я пытаюсь сделать анаграмму как это:

["demo", "dome", "mode"] 
["neon", "none"] 
(etc) 

Так что я получил этот код:

result = {} 

words.each do |word| 
    key = word.split('').sort.join 
    if result.has_key?(key) 
    result[key].push(word) 
    else 
    result[key] = [word] 
    end 
end 

result.each do |k, v| 
    puts "------" 
    p v 
end 

Я понимаю, как слово получило раскол и присоединилось, но эта часть здесь не ясна для меня:

if result.has_key?(key) 
    result[key].push(word) 
    else 
    result[key] = [word] 
    end 

В приведенном выше коде довольно очевидно, что результатом является пустой хеш, и теперь мы спрашиваем, есть ли у него ключ отсортированного/присоединенного ключа через if result.has_key?(key). Как это работает? Зачем спрашивать пустой хэш, если он имеет ключ выбранного ключа через итерацию слов?

result[key].push(word) также не ясен для меня. Так этот код вводит ключ в результат как его ключ? или само слово?

result[key] = [word] этот тоже. Он добавляет слово внутри массива с ключом?

Извините, я немного смущен.

+2

Мне нравится титул этого «вопроса», –

ответ

5

results пуст только на первой итерации цикла. Линия

if result.has_key?(key) 

проверяет, если key создается путем сортировки писем в текущем word существует, и в случае первой итерации, когда она пуста, да, это, очевидно, не существует на этот раз, но он все равно должен проверять и другое время.

Теперь, когда конкретный key еще не существует в results, что key добавляют к results и новый массив, содержащий текущий word добавляется в качестве значения для этого key, в линии

result[key] = [word] 

Когда key уже существует в results, это означает, что имеется уже массив, содержащий по меньшей мере один word, поэтому в этот массив добавляется ток word, в строке

result[key].push(word) 

Пошаговое что происходит:

words = ['demo', 'neon', 'dome', 'mode', 'none'] 

// first iteration of the loop 
word = 'demo' 
key = 'demo' // the letters in "demo" happen to already be sorted 
Is 'demo' a key in results? 
results is currently {} 
No, 'demo' is not a key in {} 
Add 'demo' as a key, and add an array with 'demo' inside 
results is now { 'demo' => ['demo'] } 

// second iteration 
word = 'neon' 
key = 'enno' 
Is 'enno' a key in results? 
results is currently { 'demo' => ['demo'] } 
No, 'enno' is not a key in { 'demo' => ['demo'] } 
Add 'enno' as a key, and add an array with 'neon' inside 
results is now { 'demo' => ['demo'], 'enno' => ['neon'] } 

// third iteration 
word = 'dome' 
key = 'demo' 
Is 'demo' a key in results? 
results is currently { 'demo' => ['demo'], 'enno' => ['neon'] } 
Yes, 'demo' is a key in { 'demo' => ['demo'], 'enno' => ['neon'] } 
Add 'dome' to the array at key = 'demo' 
results is now { 'demo' => ['demo', 'dome'], 'enno' => ['neon'] } 

// ... and so on 
1

Есть инструменты, которые помогут вам понять этот материал по своему усмотрению. Вот пример использования Seeing Is Believing с Vim:

words = ['demo', 'mode'] 

result = {} 

words.each do |word| # => ["demo", "mode"] 
    key = word # => "demo", "mode" 
     .split('') # => ["d", "e", "m", "o"], ["m", "o", "d", "e"] 
     .sort # => ["d", "e", "m", "o"], ["d", "e", "m", "o"] 
     .join # => "demo", "demo" 
    result # => {}, {"demo"=>["demo"]} 
    if result.has_key?(key) 
    result[key].push(word) # => ["demo", "mode"] 
    else 
    result[key] = [word] # => ["demo"] 
    end 
    result # => {"demo"=>["demo"]}, {"demo"=>["demo", "mode"]} 
end 

result.each do |k, v| # => {"demo"=>["demo", "mode"]} 
    puts "------" 
    p v 
end 

# >> ------ 
# >> ["demo", "mode"] 

Другие инструменты я использую, IRB и монтировку.

0

Учитывая, что у вас есть ответы, которые дают хорошие объяснения вашей проблемы, я хотел бы представить еще несколько подобных Ruby-подходов, которые можно было бы использовать.Все эти методы создают хэш-код h, значения которого представляют собой массивы слов, которые являются анаграммами друг друга, которые могут быть извлечены из хэша, выполнив h.values.

Использование Enumerable#group_by и Array#sort

Это, возможно, самый прямой подход.

words.group_by { |w| w.each_char.sort }.values 
    #=> [["demo", "dome", "mode"], ["none", "neon"], ["tied", "diet", "edit", "tide"], 
    # ["evil", "live", "veil", "vile"], ["fowl", "wolf", "flow"]] 

group_by производит

words.group_by { |w| w.each_char.sort } 
    #=> {["d", "e", "m", "o"]=>["demo", "dome", "mode"], 
    # ["e", "n", "n", "o"]=>["none", "neon"], 
    # ["d", "e", "i", "t"]=>["tied", "diet", "edit", "tide"], 
    # ["e", "i", "l", "v"]=>["evil", "live", "veil", "vile"], 
    # ["f", "l", "o", "w"]=>["fowl", "wolf", "flow"]} 

, после чего это просто вопрос извлечения значения этой хэш.

построить хеш путем добавления слова в массивы, которые являются значением хэша

words.each_with_object({}) { |w,h| (h[w.each_char.sort] ||= []) << w }.values 
    #=> [["demo", "dome", "mode"], ["none", "neon"], ["tied", "diet", "edit", "tide"], 
    # ["evil", "live", "veil", "vile"], ["fowl", "wolf", "flow"]] 

Когда «демо» передаются в блок хэш h пуст, поэтому блок переменных присваиваются значение

w = "demo" 
h = {} 

и расчет выполняется блок:

h[["d", "e", "m", "o"]] ||= []) << w 

, как

w.each_char.sort 
    #=> ["d", "e", "m", "o"] 

Рубин первым расширяет это

h[["d", "e", "m", "o"]] = (h[["d", "e", "m", "o"]] ||= []) << "demo" 

В этот момент h не имеет ключей, поэтому h[["d", "e", "m", "o"]] вычисляется в nil. Таким образом, выражение становится

h[["d", "e", "m", "o"]] = (nil ||= []) << "demo" 
         = [] << "demo" 
         = ["demo"] 

Позже, когда «купол» встречается,

w = "dome" 
w.each_char.sort 
    #=> ["d", "e", "m", "o"] 

и так h уже имеет этот ключ, расчет блока заключается в следующем.

h[["d", "e", "m", "o"]] = (h[["d", "e", "m", "o"]] ||= []) << "dome" 
         = (["demo"] ||= []) << "dome" 
         = ["demo"] << "dome" 
         = ["demo", "dome"] 

Получает

words.each_with_object({}) { |w,h| (h[w.each_char.sort] ||= []) << w } 
    #=> {["d", "e", "m", "o"]=>["demo", "dome", "mode"], 
    # ["e", "n", "n", "o"]=>["none", "neon"], 
    # ["d", "e", "i", "t"]=>["tied", "diet", "edit", "tide"], 
    # ["e", "i", "l", "v"]=>["evil", "live", "veil", "vile"], 
    # ["f", "l", "o", "w"]=>["fowl", "wolf", "flow"]} 

, после чего извлекается значение.

Вариант этого заключается в следующем.

words.each_with_object(Hash.new { |h,k| h[k] = []}) { |w,h| 
    h[w.each_char.sort] << w }.values 

Смотрите документ для Hash::new для объяснения, в частности, обсуждение значений по умолчанию данных блоком.

Для каждого слова, объединить хэш, имеющий один ключ в первоначально пустой хэш

words.each_with_object({}) { |w,h| 
    h.update(w.each_char.sort=>[w]) { |_,o,n| o+n } }.values 

Аргумент w.each_char.sort=>[w] представляет собой сокращенную { w.each_char.sort=>[w] }.

Это использует форму Hash#update (ака merge!), который использует блок «разрешение» (здесь { |_,o,n| o+n }) для определения значений ключей, которые присутствуют в обоих хешей начинают слиты. См. Документ для описания трех ключей этого блока (первая блок-переменная, общий ключ, не используется в этом расчете, поэтому я использовал символ подчеркивания).

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