Ruby's Enumerable ist dein Freund, insbesondere each_with_object die eine Form von reduce ist.
Sie müssen zuerst die fruits
Wert:
fruits = fruit_counts.each_with_object([]) do |fruit, list|
aggregate = list.detect { |f| f[:name] == fruit.name }
if aggregate.nil?
aggregate = { name: fruit.name, count: 0 }
list << aggregate
end
aggregate[:count] += fruit.count
aggregate[:count2] += fruit.count2
end
UPDATE: hinzugefügt mehrere Zählungen innerhalb der einzelnen fruchtig-Schleife.
Die oben genannten werden jedes Fruchtobjekt serialisieren - eine Zählung für jede Frucht beibehalten - in einen Hash und aggregieren sie in ein leeres list
Array und weisen das Aggregat-Array der Variablen fruits
zu. Jetzt
, erhalten den Gesamtwert:
total = { name: 'AllFruits', count: fruit_counts.map { |f| f.count + f.count2 }.reduce(:+) }
UPDATE: insgesamt unter Berücksichtigung mehrere Zählung innerhalb einer einzigen Schleife Attribute.
die oben map
S die fruit_counts
Array, wobei jedes Attribut des Objekts count
Rupfen, in einer Reihe von ganzen Zahlen ergibt. Dann erhält reduce
die Summe der Ganzzahlen des Arrays.
legte sie nun alle zusammen in der Zusammenfassung:
fruits_summary = { fruits: fruits, total: total }
Sie dies durch die Einführung eines FruitCollection
Objekt in einem OOP-Stil, der die Enumerable
Modul verwendet formalisieren können:
class FruitCollection
include Enumerable
def initialize(fruits)
@fruits = fruits
end
def summary
{ fruits: fruit_counts, total: total }
end
def each(&block)
@fruits.each &block
end
def fruit_counts
each_with_object([]) do |fruit, list|
aggregate = list.detect { |f| f[:name] == fruit.name }
if aggregate.nil?
aggregate = { name: fruit.name, count: 0 }
list << aggregate
end
aggregate[:count] += fruit.count
aggregate[:count2] += fruit.count2
end
end
def total
{ name: 'AllFruits', count: map { |f| f.count + f.count2 }.reduce(:+) }
end
end
Jetzt ist Ihre fruit_count
passieren Array in das Objekt:
fruit_collection = FruitCollection.new fruit_counts
fruits_summary = fruit_collection.summary
Der Grund, warum das obige funktioniert, ist das Überschreiben der each
Methode, die Enumerable
unter der Haube für jede enumerable
Methode verwendet. Dies bedeutet, dass wir each_with_object
, reduce
und map
aufrufen können (unter anderem aufgelistet in den oben genannten Aufzählungsdokumenten) und es wird über die fruits
iterieren, da wir es in der obigen each
Methode angegeben haben.
Hier ist ein Artikel auf Enumerable.
UPDATE:
class FruitCount
attr_accessor :name, :count1, :count2
def initialize(name, count1, count2)
@name = name
@count1 = count1
@count2 = count2
end
def total
@count1 + @count2
end
end
Dann benutzen Sie einfach fruit.total
, wenn Sie die Summen aggregieren müssen: Ihre Mehrfachzählungen leicht durch Zugabe von insgesamt Attribut zu Ihrem Obst Objekt hinzugefügt werden können
fruit_counts.map(&:total).reduce(:+)
Aber es gibt Ihnen jede FruitCount zur Liste hinzufügen, und ich möchte, dass durch die Frucht Namen auch aggregieren. Sehen Sie sich das Ergebnis im Beispiel an. Ich habe es geschafft, es mit einer einzigen Injektion zu tun, in jeder Iteration nach der Frucht zu suchen, die ich zu seiner Zählung hinzufügen möchte, aber ich will immer noch einen einfacheren Weg. –
Große Antwort. Ein paar kleine Verbesserungen: 1) 'fruit_counts' benötigt' each_with_object' nicht, da '@ fruits' bereits ein Array/enumerable ist:' map {| fruit | {Name: Frucht.Name, ...}} '. 2) Sie können zwei Läufe der Schleife vermeiden und 'total' vereinfachen:' count: reduce (0) {| total, fruit | total + fruit.count} '. – coreyward
Beachten Sie in dem Beispiel, dass ich mehrere FruitCounts für jede Frucht wie 'Orange' haben werde ... Ich möchte auch nach Obstnamen aggregieren, bitte schauen Sie sich das Beispiel an. Ich glaube, das Schwierigste hier ist, es mit den weniger Läufen zu lösen. Übrigens mag ich wirklich, wie die Antwort erklärt wurde –