Как должен работать each_with_object?

Новичок в рубине, я пытаюсь выяснить, как each_with_object должен быть использован.

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

> (1..3).each_with_object(0) {|i,sum| sum+=i}
=> 0

Эй, я бы предположил, что результат будет 6! Где моя ошибка?

3 ответа

Решение

each_with_object не работает с неизменяемыми объектами, такими как целое число.

(1..3).each_with_object(0) {|i,sum| sum += i} #=> 0

Это потому что each_with_object перебирает коллекцию, передавая каждый элемент и данный объект в блок. Он не обновляет значение объекта после каждой итерации и возвращает исходный данный объект.

Это будет работать с хешем, так как изменение значения ключа хеша само по себе меняет его для исходного объекта.

(1..3).each_with_object({:sum => 0}) {|i,hsh| hsh[:sum] += i}
#=> {:sum => 6}

String объекты интересный случай. Они изменчивы, поэтому вы можете ожидать, что следующее вернет "abc"

("a".."c").each_with_object("") {|i,str| str += i} # => ""

но это не так. Это потому что str += "a" возвращает новый объект, а исходный объект остается прежним. Однако если мы сделаем

("a".."c").each_with_object("") {|i,str| str << i} # => "abc"

это работает, потому что str << "a" изменяет исходный объект

Для получения дополнительной информации смотрите документацию ruby ​​для each_with_object

Для вашей цели используйте инъекцию

(1..3).inject(0) {|sum,i| sum += i} #=> 6
# or
(1..3).inject(:+) #=> 6

Простой, но распространенный пример использования each_with_object это когда вам нужно построить хеш в зависимости от элементов в массиве. Очень часто вы видите что-то вроде:

hash = {}
[1, 2, 3, 4].each { |number| hash[number] = number**2 }
hash

С помощью each_with_object избегает явной инициализации и возврата hash переменная.

[1,2,3,4].each_with_object({}) { |number, hash| hash[number] = number**2 }

Я советую читать документы для inject, tap а также each_with_index, Эти методы полезны, когда вы стремитесь к короткому и читабельному коду.

Документация Enumerable#each_with_object очень понятно

Повторяет данный блок для каждого элемента с заданным произвольным объектом и возвращает первоначально заданный объект.

В твоем случае, (1..3).each_with_object(0) {|i,sum| sum+=i} Вы проходите 0, который является неизменным объектом. Таким образом, здесь первый объект each_with_object метод 0, поэтому метод возвращает 0 Это работает на это рекламируется. Смотрите ниже как each_with_object работает,

(1..3).each_with_object(0) do |e,mem|
    p "#{mem} and #{e} before change"
    mem = mem + e
    p mem
end

# >> "0 and 1 before change"
# >> 1
# >> "0 and 2 before change"
# >> 2
# >> "0 and 3 before change"
# >> 3

Это означает, что в каждом проходе, mem устанавливается на исходный переданный объект. Вы можете думать о первом проходе mem является 0 затем в следующем проходе mem является результатом mem+=e, т.е. mem будет 1.Но НЕТ, в каждом проходе mem ваш начальный объект, который 0,

Другие вопросы по тегам