2011-01-11 6 views
13

Dada una matriz ordenada de n enteros, como el siguiente:calcular las diferencias entre elementos de la matriz

ary = [3, 5, 6, 9, 14] 

I necesidad de calcular la diferencia entre cada elemento y el siguiente elemento de la matriz. Utilizando el ejemplo anterior, me gustaría terminar con:

[2, 1, 3, 5] 

La matriz de principio pueden tener 0, 1 o muchos elementos en ella, y los números I a ser el manejo será mucho más grande (I va a utilizar marcas de tiempo de época). Intenté lo siguiente:

times = @messages.map{|m| m.created_at.to_i} 
left = times[1..times.length-1] 
right = times[0..times.length-2] 
differences = left.zip(right).map { |x| x[0]-x[1]} 

Pero mi solución anterior no es óptima ni ideal. ¿Alguien puede darme una mano?

Respuesta

38
>> ary = [3, 5, 6, 9, 14] #=> [3, 5, 6, 9, 14] 
>> ary.each_cons(2).map { |a,b| b-a } #=> [2, 1, 3, 5] 

Editar: Sustituido inject con map.

+0

Eso es increíblemente concisa. Gracias por la increíble respuesta. –

+4

¡Agradable! No sabía sobre 'each_cons' antes. Esta es una versión más corta de lo mismo: 'ary.each_cons (2) .map {| a, b | b-a} '. – Heikki

+0

Como nota al margen: es importante dar nombre a las abstracciones: [(a, b), (b, c), (c, d), ...] se llaman "combinaciones de pares". Y de hecho enumerable.each_cons (2) .map es la mejor manera de hacerlo en Ruby (gracias a los enumeradores todos los métodos de cada_xyz ahora se pueden usar "funcionalmente") – tokland

1

Una alternativa:

a.map.with_index{ |v,i| (a[i+1] || 0) - v }[0..-2] 

no funciona en Rubí, donde 1,8 map requiere un bloque en lugar de devolver un enumerador.

7

similares pero más concisa:

[3, 5, 6, 9, 14].each_cons(2).collect { |a,b| b-a } 
+2

Aún más conciso si reemplaza 'collect' con' map':) Tenga en cuenta que 'each_cons' no está disponible en 1.8.6, pero está disponible en 1.8.7. – Phrogz

+0

Tienes razón, por supuesto, 'map' es mejor que' inject' aquí. –

Cuestiones relacionadas