En el siguiente programa, el ciclo parece detenerse después de 2 ejecuciones, en lugar de 3 como se esperaba. El valor esperado de sum_of_sums es 35, pero aquí es 23.
ary = [1,2,3,4] sum_of_sums = 0 ary.each do # => [1, 2, 3, 4] n=ary.shift # => 1, 2 sum_of_products = ary.reduce(0) do |memo,e| # => [2, 3, 4], [3, 4] memo+(n*e) # => 2, 5, 9, 6, 14 end sum_of_sums += sum_of_products # => 9, 23 end sum_of_sums # => 23Funciona como se esperaba con [1,2,3]:
ary = [1,2,3] sum_of_sums = 0 ary.each do # => [1, 2, 3] n=ary.shift # => 1, 2 sum_of_products = ary.reduce(0) do |memo,e| # => [2, 3], [3] memo+(n*e) # => 2, 5, 6 end sum_of_sums += sum_of_products # => 5, 11 end sum_of_sums # => 11 Estoy tratando de escribir un programa que, para un conjunto [a,b,c,d], calcule ab + ac + ad + bc + bd + cd . No sé cómo expresar este patrón más que con el ejemplo. Y sí, probablemente podría hacerlo de manera más explícita, o más fácilmente al factorizar los términos, ¡pero quiero saber por qué este bucle no funciona!
EDITAR: Gracias amigos... Parece que el problema era que la matriz se estaba modificando con #shift dentro del ciclo #each . Terminé teniendo éxito con esto:
ary = [1,2,3,4] sum = 0 until ary.count==1 do sum += ary.shift * ary.sum end sumTeniendo en cuenta que su pregunta ha sido respondida, me gustaría sugerir una forma más eficiente de realizar el cálculo. Darse cuenta de
(a+b+c)**2 = a**2 + b**2 + c**2 + 2*(ab + ac + bc)asi que
ab + ac + bc = ((a+b+c)**2 - (a**2 + b**2 + c**2))/2Por lo tanto, podemos escribir
def sum_of_cross_terms(arr) ((arr.sum)**2 - arr.reduce(0) { |t,n| t + n**2 })/2 end sum_of_cross_terms([1, 2, 3]) #=> 11 sum_of_cross_terms([1, 2, 3, 4]) #=> 35 Vemos que la complejidad computacional de este cálculo es O( arr.size ), mientras que el enfoque de fuerza bruta es O( (arr.size)**2 ). Un ejemplo de esto último es
def sum_of_cross_terms(arr) arr.combination(2).sum { |a,b| a*b } endComo dijo spickermann, está modificando la matriz que está iterando mientras la itera. Esto producirá resultados inesperados.
Si desea usar shift , construya el ciclo usando algo que no se ve afectado por el cambio (modificación) de la matriz.
(ary.size-1).times.map { ary.shift * ary.sum }.sumSin modificar la matriz, se vuelve un poco más detallado:
(ary.size-1).times.map { |i| ary[i] * ary.drop(i+1).sum }.sumTambién puede hacer un duplicado antes de la iteración:
ary.dup.map { ary.shift * ary.sum }.sum O usando with_index :
ary.map.with_index { |n, i| n * ary.drop(i+1).sum }.sumHay muchas otras formas de hacer esto también, pero espero que esto te dé algunas ideas.