2016-06-25 12 views
-1

Wir haben Arrays von Hashes, von denen jeder hat eine value Eigenschaft und eine timeframe Eigenschaft:Summe aus einer Struktur, die in mehreren, ähnlich Arrays

result1 = [ 
    {"value"=>1, "timeframe"=>{"start"=>"2016-05-27T00:00:00.000Z", "end"=>"2016-05-28T00:00:00.000Z"}}, 
    {"value"=>1, "timeframe"=>{"start"=>"2016-05-28T00:00:00.000Z", "end"=>"2016-05-29T00:00:00.000Z"}}, 
    {"value"=>1, "timeframe"=>{"start"=>"2016-05-29T00:00:00.000Z", "end"=>"2016-05-30T00:00:00.000Z"}} 
] 

result2 = [ 
    {"value"=>2, "timeframe"=>{"start"=>"2016-05-27T00:00:00.000Z", "end"=>"2016-05-28T00:00:00.000Z"}}, 
    {"value"=>2, "timeframe"=>{"start"=>"2016-05-28T00:00:00.000Z", "end"=>"2016-05-29T00:00:00.000Z"}}, 
    {"value"=>2, "timeframe"=>{"start"=>"2016-05-29T00:00:00.000Z", "end"=>"2016-05-30T00:00:00.000Z"}} 
] 

Wir brauchen ein Array zu erstellen, die die Summe der sein wird, value Eigenschaft jedes Element in der passenden Position, so etwas wie:

[3, 3, 3] 

EDIT: Bearbeitet die Frage einfacher zu sein und hoffentlich weniger verwirrend. Sorry für die Leute, die versucht haben, dabei zu helfen, wirklich Ihre Eingabe zu schätzen

+1

Wie die 'ist„start“' und '„Ende“' Werte in Bezug auf den ': Datumswert? Unklar. – sawa

+1

Ich stimme mit Sawa, dass war nicht klar, dass Sie nur das Startdatum jedes Zeitrahmens in den resultierenden Hashes wollte. Meine Antwort war wahrscheinlich deswegen falsch. Und du hast es nicht einmal kommentiert. Ich bin enttäuscht. – Raffael

Antwort

2
[result1, result2].reduce(:+) 
        .map { |e| [e['timeframe']['start'], e['value']] } 
        .each_with_object(Hash.new(0)) { |(d, v), memo| memo[d] += v } 
#⇒ { 
#  "2016-05-27T00:00:00.000Z" => 3, 
#  "2016-05-28T00:00:00.000Z" => 3, 
#  "2016-05-29T00:00:00.000Z" => 3 
# } 

Werte Um aus nur von Hash, Hash#values verwenden.

+0

Ist reduce anders als '(result1 + result2)'? – tmartin314

+1

Nein, sie sind gleich. Ich wechselte zu 'reduce (: +)', um die Absicht zu verdeutlichen. Ich habe 'reduce' verwendet, weil es ein Array von' result' Arrays geben könnte, und in diesem Fall ist es schwierig, sie mit inline '+' zu addieren. – mudasobwa

+0

Großartig, was die Pfeife macht das gleiche? Ich habe es nie gesehen – tmartin314

2

Ich schlage vor, Sie zuerst einen Hash mit Daten als Schlüssel und die Summen als Werte zu konstruieren. Dies ist eine nicht-triviale Hash-Konstruktion, daher empfehle ich, sie inkrementell mit each anstatt mit einer map durchzuführen.

totals_per_date = Hash.new(0) 
results = [*result1, *result2] 
results.each do |record| 
    first_day = record["timeframe"]["start"].to_date 
    last_day = record["timeframe"]["end"].to_date 
    (first_day..last_day).each do |day| 
    totals_per_date[day] += record["value"] 
    end 
end 

, dass auf das angegebene Ziel Hash-Transformation ist ein guter Anwendungsfall für map:

graph_data = totals_per_date.map{ |day, total| {date: day, total: total} } 
1

Ihr könnte Ihr Rückgabewert einen Hash zu machen, anstatt ein Array von Hashes betrachten:

(result1+result2).each_with_object({}) { |g,h| 
    h.update(g["timeframe"]["start"]=>g["value"]) { |_,o,n| o+n } } 
    #=> {"2016-05-27T00:00:00.000Z"=>3, 
    # "2016-05-28T00:00:00.000Z"=>3, 
    # "2016-05-29T00:00:00.000Z"=>3} 

Diese Form von Hash#update (aka Hash#merge!), die einen Block ({ |k,o,n| o+n }), um die Werte zu bestimmen beschäftigt verwendet von Schlüssel, die in beiden Hashes vorhanden sind, werden zusammengeführt. Im Dokument finden Sie die Bedeutung der drei Blockvariablen. Der gemeinsame Schlüssel, k, wird nicht in der Blockberechnung verwendet. Daher habe ich ihn wie üblich in _ geändert.

Wenn, wie gesagt, wollen Sie ein Array von Hashes zurückzukehren, gibt es einen weiteren Schritt:

(result1+result2).each_with_object({}) { |g,h| 
    h.update(g["timeframe"]["start"]=>g["value"]) { |_,o,n| o+n } }. 
    map { |k,v| { date: k, value: v } } 
    #=> [{:date=>"2016-05-27T00:00:00.000Z", :value=>3}, 
    # {:date=>"2016-05-28T00:00:00.000Z", :value=>3}, 
    # {:date=>"2016-05-29T00:00:00.000Z", :value=>3}]