2017-09-30 2 views

Répondre

2

Voici deux façons de le faire.

arr = [[ '01-01-2001', 4 ], [ '01-01-2001', 5 ], [ '01-01-2001', 6 ], [ '01-02-2001', 7]] 

Utilisez Enumerable#group_by

arr.group_by(&:first).transform_values { |v| v.sum(&:last).fdiv(v.size) } 
    #=> {"01-01-2001"=>5.0, "01-02-2001"=>7.0} 

Voir Hash#transform_values, Array#sum et Numeric#fdiv.

La première étape consiste à regrouper les éléments par date:

arr.group_by(&:first) 
    #=> {"01-01-2001"=>[["01-01-2001", 4], ["01-01-2001", 5], ["01-01-2001", 6]], 
    # "01-02-2001"=>[["01-02-2001", 7]]} 

utilisation Hash#update

De cette façon, utilise la forme de Hash#update (aka merge!) qui emploie un bloc pour déterminer les valeurs de les clés présentes dans les deux hachages sont fusionnées.

arr.each_with_object({}) do |(k,v), h| 
    h.update(k=>[v, 1]) { |_k, (otot, onbr), (ntot, nnbr)| [otot+ntot, onbr+1] } 
end.transform_values { |tot, nbr| tot.fdiv(nbr) } 

Voir la doc pour une explication des trois variables de blocs utilisés dans le bloc qui retourne la valeur de chaque clé qui est contenue dans les deux hash fusionnées. Le hachage h en cours de construction contient, pour chaque chaîne de date distincte, un tableau à 2 éléments dont la première valeur est un total cumulé de valeurs pour la date donnée et dont la deuxième valeur est le nombre d'occurrences de cette date. Garder juste le total cumulé de toutes les valeurs est bien sûr plus économe en espace que de maintenir un tableau de toutes les valeurs, comme cela est fait avec la méthode group_by.

Notez que Ruby permet h.update(k=>[v, 1]) comme raccourci pour h.update({ k=>[v, 1] }).