Intenté implementar reduce usando llaves, pero no pude hacerlo funcionar. Se supone que la función toma una matriz de palabras (símbolos o cadenas) y crea un hash donde las claves son las palabras y los valores son la longitud de las palabras. Aquí está mi intento de llaves:
def find_word_lengths(word_list) word_list.reduce(Hash.new(0)) { |hash,word| hash[word] = word.length} end
Sigo recibiendo el undefined method '[]=' for 3:Integer
.
Cuando lo implemento con do
en lugar de llaves, funciona, pero solo cuando devuelvo el acumulador al final del bloque de reducción.
def find_word_lengths(word_list) word_list.reduce(Hash.new(0)) do |hash,word| hash[word] = word.length hash end end
Puedo ver por qué funciona el segundo, pero no entiendo por qué no funciona el primero. Mi comprensión de reduce es que devuelve el acumulador implícitamente después de ejecutar la matriz a la que se llama. Al menos, cuando escribo una llamada de función de reducción que se reduce a un número, automáticamente devuelve la suma
my_numbers = [5, 6, 7, 8] my_numbers.reduce(1000) { |sum, number| sum + number } #=>1026
¿Reduce se comporta de manera diferente según el tipo de acumulador?
En su primer ejemplo, devuelve el resultado de asignar word.length
al hash[word]
, es decir, word.length
en sí misma. Por lo tanto, la iteración de la sección del ciclo recuperará la longitud de la primera palabra de su word_list
como su argumento.
En su segundo ejemplo, está devolviendo explícitamente el hash en el bloque (que luego funciona).
Una versión equivalente de una sola línea con llaves para su versión funcional de varias líneas es
word_list.reduce(Hash.new(0)) { |hash, word| hash[word] = word.length; hash }
En lugar de usar reduce
, también podría usar each_with_object
en su lugar, lo que siempre producirá el objeto original en cada iteración:
word_list.each_with_object(Hash.new(0)) { |hash, word| hash[word] = word.length }
El acumulador NO se devuelve implícitamente. Esta es la suposición que rompe el resto de su análisis.
El se indica en los documentos si lee cuidadosamente:
... En cualquier caso, el resultado se convierte en el nuevo valor de memo . ..
De lo que se trata es del resultado de la ejecución del bloque, ya sean llaves o do/end , se convierte en el nuevo valor de memo en la siguiente ronda.
Entonces, tanto las llaves como do/end funcionan exactamente igual, solo que asumiste que la nota se devolvió implícitamente, cuando no es así.
Si analiza su código ahora con este nuevo conocimiento, debería comprender por qué algunos de los ejemplos funcionaron y otros no.
Recuerde, la última declaración dentro del bloque será el valor de la nota en la próxima iteración.