2011-01-11 2 views
13

Étant donné un tableau trié des entiers n, comme suit:différences entre les éléments de réseau

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

I nécessité de calculer la différence entre chaque élément et l'élément suivant dans la matrice. En utilisant l'exemple ci-dessus, je finirais avec:

[2, 1, 3, 5] 

Le tableau commençant peut avoir 0, 1 ou plusieurs éléments, et les chiffres que je vais être la manipulation sera beaucoup plus grande (je vais utiliser timestamps de l'époque). J'ai essayé ce qui suit:

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]} 

Mais ma solution ci-dessus est à la fois pas optimale, et pas idéal. Quelqu'un peut-il me donner un coup de main?

Répondre

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] 

Edit: Remplacée inject avec map.

+0

C'est étonnamment concis. Merci pour la réponse géniale. –

+4

Bien! Je ne connaissais pas 'each_cons' avant. C'est une version un peu plus courte de la même chose: 'ary.each_cons (2) .map {| a, b | b-a} '. – Heikki

+0

En remarque: il est important de donner un nom aux abstractions: [(a, b), (b, c), (c, d), ...] sont appelées "combinaisons par paires". Et en effet enumerable.each_cons (2) .map est la meilleure façon de le faire dans Ruby (grâce aux énumérateurs toutes les méthodes each_xyz peuvent maintenant être utilisées "fonctionnellement") – tokland

1

Une alternative:

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

ne fonctionne pas dans Ruby 1.8 où map nécessite un bloc au lieu de retourner un recenseur.

7

similaires mais plus concise:

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

Encore plus concis si vous remplacez 'collect' par' map': Notez que 'each_cons' n'est pas disponible en 1.8.6, mais est disponible en 1.8.7. – Phrogz

+0

Vous avez bien sûr raison, 'map' est mieux que' injecter' ici. –

Questions connexes