2010-05-17 10 views
1

Disons que je le tableau suivant:Comment ajouter la valeur à toutes les valeurs précédentes dans le tableau

my_array = [1, 5, 8, 11, -6] 

Je dois itérer sur ce tableau et ajouter les valeurs avant la valeur actuelle ensemble. Un exemple sera probablement plus facile à comprendre. Je dois retourner un tableau qui devrait ressembler à ceci:

final_array = [1, 6, 14, 25, 19] 

J'ai essayé de faire quelque chose comme ceci:

my_array.collect {|value| value + previous_values } 

Mais, évidemment, cela ne fonctionne pas parce que je ne peux pas comprendre comment pour obtenir les valeurs précédentes dans le tableau. Je suis un programmeur de noob donc c'est peut-être plus facile que je le fais. Je suis assez sûr que je dois utiliser soit recueillir ou injecter, mais je n'arrive pas à comprendre comment faire cela.

Toute aide serait appréciée.

+0

cool. Merci tout le monde. Je vais donner à ceux-ci un coup de feu. Très apprécié. – James

Répondre

6

votre propre tentative avec collect était déjà très proche; continuez simplement à additionner les valeurs précédentes au fur et à mesure.

my_array = [1, 5, 8, 11, -6] 
previous_values = 0 
my_array.collect { |value| previous_values += value } 
# => [1, 6, 14, 25, 19] 
1
my_array.each_index{|i| my_array[i] += my_array[i-1] if i>0 } 

ou

my_array.inject([]){|memo, item| memo << item + memo.last.to_i } 
+0

injecter est peu susceptible de fonctionner comme memo.last retournera nil initialement. – Anton

+0

Oui, vous avez raison. Je pensais qu'il va convertir automatiquement en int, mais non, donc ajouté explicitement 'to_i'. –

+0

Semble inutilement complexe d'avoir à faire un cas particulier du premier élément dans les deux solutions. – Arkku

3
x = 0 
[1, 5, 8, 11, -6].map {|a| x = x +a } 
1

Vous pouvez utiliser ceci:

my_array = [1, 5, 8, 11, -6] 
final_array = [] 

my_array.inject(0) {|res, it| final_array << res + it; res + it} 
8

Mon premier instinct était: «C'est évidemment un balayage (alias préfixe somme), ce qui devrait être facile »:

[1, 5, 8, 11, -6].scan(:+) 

De toute évidence, j'ai lu beaucoup trop Haskell et Scala récemment, parce que il n'y a pas Enumerable#scan dans Ruby & hellip; encore:

module Enumerable 
    def scan(initial=first, &block) 
    [initial].tap {|res| 
     reduce {|acc, el| 
     block.(acc, el).tap {|el| 
      res << el 
     } 
     } 
    } 
    end 
end 

Si vous voulez Enumerable#scan à se comporter comme Enumerable#reduce, soit prendre un argument initial en option et un symbole en option, nous devons améliorer notre version légèrement avec un argument de code de massage volé Enumerable#reduce de Rubinius:

module Enumerable 
    def scan(initial=nil, sym=nil, &block) 
    args = if initial then [initial] else [] end 
    unless block_given? 
     args, sym, initial = [], initial, first unless sym 
     block = ->(acc, el) { acc.send(sym, el) } 
    end 
    [initial || first].tap {|res| 
     reduce(*args) {|acc, el| 
     block.(acc, el).tap {|e| 
      res << e 
     } 
     } 
    } 
    end 
end 

Avec cette version améliorée, l'exemple ci-dessus fonctionne maintenant:

p [1, 5, 8, 11, -6].scan(:+) 
# => [1, 6, 14, 25, 19] 

Si vous avez ce genre de problème à nouveau, dans une autre langue, rappelez-vous les termes scan et préfixe-somme, de telles fonctions sont généralement assez commun. Je ne comprends pas pourquoi Ruby ne les a pas déjà.

+0

Je partage ton instinct .... C'est assez ridicule ça n'a pas été un builtin depuis le début ... – Jonah

1

J'ai créé une gem pour cela qui pré-alloue le tableau de résultats. L'opération est très rapide, même pour Enumerables avec un grand nombre d'éléments. Contrairement aux solutions utilisant Enumerable # map, la syntaxe est exactement comme celle de Enumerable # reduce, et peut éventuellement utiliser Enumerable # reduce sous le capot au cas où #reduce serait corrigé par un singe.Le nom a été pris de la fonction de Clojure du même nom.

https://rubygems.org/gems/reductions

Pour installer:

$ gem install reductions 

Pour utiliser:

require 'reductions' 

[1, 5, 8, 11, -6].reductions(:+)   #=> [1, 6, 14, 25, 19] 
[1, 5, 8, 11, -6].reductions{|a| a + b}  #=> [1, 6, 14, 25, 19] 

# With an inital value: 
[1, 5, 8, 11, -6].reductions(1,:+)   #=> [1, 2, 7, 15, 26, 20] 
[1, 5, 8, 11, -6].reductions(1){|a| a + b} #=> [1, 2, 7, 15, 26, 20] 
Questions connexes