Проблемы с перебором массива для генерации частот в хэше - PullRequest
1 голос
/ 16 мая 2019

У меня есть массив с некоторыми другими данными (в строковом формате), и я хотел бы посчитать частоты каждого значения и сохранить его в хеш-коде, но я получаю ошибку, пытаясь это сделать.

Я хотел бы сделать что-то вроде этого:

    words = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]
    frequency = {}
    words.each{|word| frequency[word] += 1}

и получить следующий вывод:

   puts(frequency)   #{"foo" => 3, "var" => 1, "spam" => 1, "egg" => 2}

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

    prueba.rb:3:in `block in <main>': undefined method `+' for nil:NilClass (NoMethodError)

Есть ли другой способ достижения того же результата?

Ответы [ 4 ]

4 голосов
/ 16 мая 2019

Если вы запросите хеш для ключа, которого нет, вы получите nil, вот в чем проблема. Давайте сделаем 0 значением по умолчанию, если ключ отсутствует

frequency = Hash.new(0)
1 голос
/ 16 мая 2019
words = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]

words.each_with_object(Hash.new(0)) { |w, h| h[w] += 1 }
#=> {"foo"=>3, "var"=>1, "spam"=>1, "egg"=>2}

# each_with_object - это перечислитель, который выполняет итерацию, передавая каждому элементу предоставленный объект (здесь Hash.new(0)) и возвращает этот предоставленный объект в следующей итерации.

Hash.new(0) создает хеш, где значение по умолчанию любого ключа равно 0.

hash = Hash.new(0)
hash['a'] #=> 0

Мы используем это свойство значения по умолчанию и просто передаем каждое слово объекту и увеличиваем счетчик.:)

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

1 голос
/ 16 мая 2019

Когда вы пишете:

words.each{|word| frequency[word] += 1}

Это эквивалентно:

words.each{|word| frequency[word] = frequency[word] + 1}

Однако, frequency хеш пуст и frequency[word] возвращает nil - по сути, вы пытаетесь выполнить nil + 1, что приводит к получаемой вами ошибке.

Вы можете инициализировать новые элементы хэша вручную:

words.each{|word| frequency[word] ||= 0; frequency[word] += 1}

Или, как уже предлагали другие ответы, используйте frequency = Hash.new(0) в качестве ярлыка.

0 голосов
/ 16 мая 2019

Вы можете использовать это. Инициализируя его с помощью Hash.new (0)

names = ["foo", "var", "spam", "egg", "foo", "foo", "egg"]

names.inject(Hash.new(0)) { |total, e| total[e] += 1 ;total}

# {"foo"=>3, "var"=>1, "spam"=>1, "egg"=>2}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...