Подтвердить что ты не робот

Как должен работать каждый_объект?

new для ruby, я пытаюсь понять, как использовать each_with_object.

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

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

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

4b9b3361

Ответ 1

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

(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 ​​docs для each_with_object

Для вашей цели используйте inject

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

Ответ 2

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

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

В вашем случае (1..3).each_with_object(0) {|i,sum| sum+=i} вы проходите 0, что является неизменным объектом. Таким образом, здесь intial object для метода 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 is 0, а затем в следующем проходе mem является результатом mem+=e, т.е. mem будет 1. Но NO, в каждом проходе mem - ваш исходный объект, который 0.

Ответ 3

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

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

С each_with_object намного проще:

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

Советую прочитать документы для inject, tap и each_with_index. Они очень полезны, когда вам нужен короткий и читаемый код.