2010-04-21 15 views
30

Tengo dos (o más) matrices con 12 enteros en cada una (correspondientes a los valores de cada mes). Todo lo que quiero es sumarlos para que tenga una sola matriz con valores sumados para cada mes. He aquí un ejemplo con tres valores: [1,2,3] y [4,5,6] => [5,7,9]ruby: suma los miembros correspondientes de dos o más matrices

Lo mejor que pude ocurrió fue:

[[1,2,3],[4,5,6]].transpose.map{|arr| arr.inject{|sum, element| sum+element}} #=> [5,7,9] 

¿Hay una mejor manera de hacerlo? Simplemente parece algo tan básico querer hacer.

Respuesta

41

Aquí está la versión transpose Anurag sugirió:

[[1,2,3], [4,5,6]].transpose.map {|x| x.reduce(:+)} 

Esto funciona con cualquier número de conjuntos de componentes. reduce y inject son sinónimos, pero me parece reduce para comunicarse con mayor claridad la intención del código aquí ...

+1

... o en rieles: a.transpose.map {| x | x.sum} – jjnevis

+5

@jjnevis: bueno, si estamos jugando al golf, ¿qué tal 'a.transpose.map (&: sum)' – rampion

+0

@rampion: eso es bastante escueto, ¿podrías explicar el (&: sum) bit ? Gracias – jjnevis

6

aquí está mi intento de código-golf esta cosa:

// ruby 1.9 syntax, too bad they didn't add a sum() function afaik 
[1,2,3].zip([4,5,6]).map {|a| a.inject(:+)} # [5,7,9] 

zip vuelve [1,4], [2,5], [3,6] y mapa sumas cada sub-matriz.

+0

Agradable. ¿Cómo funcionaría esto con tres o más matrices? Estoy iterando sobre un número desconocido de matrices, por lo que la transposición funciona bien porque puedo insertarlas en una matriz vacía y transponerlas. Me encanta la sintaxis ': +' para inyectar (aunque no tan bueno como un método de suma() como dices, pero los rails sí lo añaden) - no lo veo antes, gracias. – jjnevis

+0

zip es un método de Array, y acepta cualquier cantidad de matrices como parámetros. Pero no sé cómo los superaría si se crearan dinámicamente. 'transpose' parece una mejor opción para eso. Ruby generalmente cubre muchas de las funciones comúnmente utilizadas, pero donde falta, ¡Rails viene a rescatar! – Anurag

+2

diga 'aoa' es nuestra matriz de matrices, y desea calcular' [aoa [0] [0] + aoa [1] [0] + ... + aoa [-1] [0], aoa [0 ] [1] + aoa [1] [1] + ... + aoa [-1] [1], ..., aoa [0] [- 1] + aoa [1] [- 1] + .. . + aoa [-1] [- 1]] 'entonces podrías hacer' first, * rest = * aoa; first.zip (* rest) .map {| a | a.inject (&: +)} ' – rampion

5
[[1,2,3],[4,5,6]].transpose.map{|a| a.sum} #=> [5,7,9] 
+2

Tenga en cuenta que esto no funciona en Ruby simple Tal vez lo haga en Rails, [según lo sugerido por jjnevis] (http://stackoverflow.com/questions/2682411/ruby-sum-corresponding-members-of-two-arrays#comment2702699_2682983). – FriendFX

7

Para conocer la sintaxis más clara (no la más rápida), se puede hacer uso de Vector:

require 'matrix' 
Vector[1,2,3] + Vector[4,5,6] 
=> Vector[5, 7, 9] 

para múltiples vectores, que puede hacer:

arr = [ Vector[1,2,3], Vector[4,5,6], Vector[7,8,9] ] 
arr.inject(&:+) 
=> Vector[12, 15, 18] 

Si desea cargar sus matrices en vectores y suma:

arrays = [ [1,2,3], [4,5,6], [7,8,9] ] 
arrays.map { |a| Vector[*a] }.inject(:+) 
=> Vector[12, 15, 18] 
+1

Esto es definitivamente el más limpio desde una perspectiva comprensible. –

+1

Para convertir una matriz en un vector, también puede hacer 'Vector.elements ([1, 2, 3])', además de 'Vector [* a]'. –

1

@FriendFX, estás en lo correcto sobre @ user2061694 respuesta. Solo funcionó en el entorno de Rails para mí. Puede hacer que se ejecute en la llanura de Ruby si realiza los siguientes cambios ...

En el IRB

[[0, 0, 0], [2, 2, 1], [1,3,4]].transpose.map {|a| a.inject(:+)} 
=> [3, 5, 5] 


[[1,2,3],[4,5,6]].transpose.map {|a| a.inject(:+)} 
=> [5, 7, 9] 
0

Esto podría no ser la mejor respuesta, pero funciona.

array_one = [1,2,3] 
array_two = [4,5,6] 
x = 0 
array_three = [] 
while x < array_one.length 
    array_three[x] = array_one[x] + array_two[x] 
    x += 1 
end 

=>[5,7,9] 

esto podría ser más líneas de código que otras respuestas, pero es una respuesta, no obstante

+0

Me gusta este simplemente porque está muy claro lo que está pasando, pero puede limpiarlo un poco usando "array_one".each_index hacer | x | " – jjnevis

+0

esto no es muy idiomática Rubí Uso de' while' bucles es * muy * raras soluciones –

4

Humildemente siento que las otras respuestas que veo son tan complejos que podrían ser confuso para los colaboradores de código. Debería agregar un comentario explicativo, que simplemente aumenta la cantidad de texto necesario.

¿Cómo combate esto en su lugar:

a_arr = [1,2,3] 
b_arr = [4,5,6] 
(0..2).map{ |i| a_arr[i] + b_arr[i] } 

solución ligeramente diferente: (de modo que usted no está codificar duro el "2")

a_arr = [1,2,3] 
b_arr = [4,5,6] 
c_arr = [] 
a_arr.each_index { |i| c_arr[i] = a_arr[i] + b_arr[i] } 

Por último, matemáticamente hablando, esto es lo mismo pregunta como esta:

How do I perform vector addition in Ruby?

1

Para:

a = [1,2,3] 
b = [4,5,6] 

Se podría zip y luego usar reduce:

p a.zip(b).map{|v| v.reduce(:+) } 
#=> [5, 7, 9] 

O, si está seguro de que la matriz a y b siempre serán de igual longitud:

p a.map.with_index { |v, i| v + b[i] } 
#=> [5, 7, 9] 
+0

dos muy elegantes, aunque he actualizado el título para reflejar con mayor precisión la cuestión, es decir, que se trata de" dos o más "matrices, por lo que una matriz o matrices realmente. – jjnevis

4

Ahora puede usar sum en 2.4

nums = [[1, 2, 3], [4, 5, 6]] 
nums.transpose.map(&:sum) #=> [5, 7, 9] 
+0

suma también se define con los carriles 4.2.7, https://apidock.com/rails/Enumerable/sum – Obromios

Cuestiones relacionadas