Ошибка Ruby появляется только при использовании операторов print внутри блока для array.each - PullRequest
0 голосов
/ 03 марта 2012

Если я вызову функцию anagrams ниже в irb , я получу непустой хеш-контейнер, как и ожидалось. Но если вы закомментируете строку print "No Key\n", возвращенный контейнер хеша теперь пуст. Фактически для всех элементов в списке код в ветви elsif, кажется, выполняется. Либо я схожу с ума, либо здесь есть неприятный баг:

def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
        aHash = Hash.new()
        list.each { |el|
            aKey = el.downcase.chars.sort.to_a.hash
            if aHash.key?(aKey)
                # print "Has Key\n"
                aHash[aKey] << el
            elsif
                # print "No Key\n"
                aHash[aKey] = [el]
            end
        }

        return aHash
end

У меня установлены следующие версии ruby ​​ и irb :

ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-linux]
irb 0.9.6(09/06/30)

1 Ответ

6 голосов
/ 03 марта 2012

Ваша проблема в том, что вы используете elsif, где вы имеете в виду else. Это:

elsif
    print "No Key\n"
    aHash[aKey] = [el]

вводит в заблуждение форматирование, на самом деле это интерпретируется как:

elsif(print "No Key\n")
    aHash[aKey] = [el]

но print возвращает nil, поэтому логика выглядит следующим образом:

elsif(nil)
    aHash[aKey] = [el]

и nil ложно в логическом контексте, поэтому aHash[aKey] = [el] никогда не встречается. Если вы удалите print, то получите следующее:

elsif(aHash[aKey] = [el])

и назначение происходит; присваивание также верно в логическом контексте (потому что массив), но в этом случае достоверность не имеет значения.

Вы хотите использовать else здесь:

if aHash.key?(aKey)
    aHash[aKey] << el
else
    aHash[aKey] = [el]
end

Еще лучше было бы использовать Hash с массивом (через блок) в качестве значения по умолчанию:

aHash = Hash.new { |h, k| h[k] = [ ] }

и тогда вам вообще не понадобится if, вы можете просто сделать это:

list.each do |el|
    aKey = el.downcase.chars.sort.to_a.hash
    aHash[aKey] << el
end

И вы можете использовать что угодно в качестве ключа в Ruby Hash, поэтому вам даже не нужно .to_a.hash, вы можете просто использовать сам массив в качестве ключа; Более того, sort даст вам массив, так что вам даже не понадобится to_a:

list.each { |el| aHash[el.downcase.chars.sort] << el }

Кто-то, вероятно, пожалуется на return в конце вашего метода, поэтому я сделаю это: вам не нужен return в конце вашего метода, просто скажите aHash, и это будет возвращаемое значение метода:

def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
    aHash = Hash.new { |h, k| h[k] = [ ] }
    list.each { |el| aHash[el.downcase.chars.sort] << el }
    aHash
end

Вы также можете использовать each_with_object, чтобы сжать его еще больше:

def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
    list.each_with_object(Hash.new { |h, k| h[k] = [ ] }) do |el, h|
        h[el.downcase.chars.sort] << el
    end
end

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

def anagrams(list = ['cars', 'for', 'potatoes', 'racs', 'four','scar', 'creams', 'scream'])
    h = Hash.new { |h, k| h[k] = [ ] }
    list.each_with_object(h) { |el, h| h[el.downcase.chars.sort] << el }
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...