Ich bin etwas neu in Clojure. Ich kann mir nicht vorstellen, wie ich etwas tun soll, das so einfach zu sein scheint. Ich kann es einfach nicht sehen. Ich habe eine Reihe von Vektoren. Nehmen wir an, jeder Vektor hat zwei Werte, die Kundennummer und Rechnungsnummer darstellen, und jeder der Vektoren repräsentiert einen Verkauf eines Artikels. So würde es ungefähr so aussehen:
%Vor%Ich möchte die Anzahl der eindeutigen Kunden und einmaligen Rechnungen zählen. Also sollte das Beispiel den Vektor
erzeugen %Vor%In Java oder einer anderen imperativen Sprache würde ich jeden der Vektoren im Seq durchlaufen, die Kundennummer und Rechnungsnummer zu einem Satz hinzufügen, dann die Anzahl der Werte in jedem Satz zählen und sie zurückgeben. Ich kann den funktionalen Weg nicht sehen, dies zu tun.
Danke für die Hilfe.
EDIT: Ich hätte in meiner ursprünglichen Frage angeben sollen, dass der Seq der Vektoren in den 10 Millionen von Millionen ist und tatsächlich mehr als nur zwei Werte hat. Also möchte ich nur einmal durch den Seq gehen und diese einzigartigen Zählungen (und auch einige Summen) auf diesem einen Durchlauf durch die Seq berechnen.
In Clojure können Sie es fast genauso machen - rufen Sie zuerst distinct
an, um eindeutige Werte zu erhalten, und verwenden Sie dann count
, um die Ergebnisse zu zählen:
Beachten Sie, dass Sie hier zuerst eine Liste von ersten und zweiten Elementen von Vektoren erhalten (Map-First / Second-Vektoren) und dann jeweils getrennt arbeiten und somit zweimal über die Sammlung iterieren. Wenn die Leistung eine Rolle spielt, können Sie dasselbe mit der Iteration tun (siehe loop
form oder tail recursion) und setzen, genau wie in Java. Um die Leistung weiter zu verbessern, können Sie auch transients
verwenden. Obwohl für Anfänger wie dich würde ich zuerst mit distinct
empfehlen.
UPD. Hier ist Version mit Schleife:
%Vor%Wie Sie sehen können, brauchen Sie keine Atome oder so etwas. Zuerst übergeben Sie den Status an jede nächste Iteration (wiederholter Aufruf). Zweitens verwenden Sie Transienten, um temporäre veränderbare Sammlungen zu verwenden (lesen Sie mehr über Transienten für Details) und vermeiden Sie so jedes Mal die Erstellung eines neuen Objekts.
UPD2. Hier ist die Version mit reduce
für die erweiterte Frage (mit Preis):
Hier halten wir Zwischenergebnisse in einem Vektor [custs invs total]
, entpacken, verarbeiten und packen sie jedes Mal wieder in einen Vektor. Wie Sie sehen können, ist das Implementieren einer solchen nichttrivialen Logik mit reduce
schwieriger (sowohl Schreiben als auch Lesen) und erfordert noch mehr Code (in loop
ed Version reicht es aus, einen weiteren Parameter für Preis-zu-Schleife-Argumente hinzuzufügen). Also stimme ich @ammaloy zu, dass für einfachere Fälle reduce
besser ist, aber komplexere Dinge mehr Konstrukte auf niedriger Ebene erfordern, wie zB loop/recur
pair.
Wie es oft der Fall ist, wenn eine Sequenz konsumiert wird, ist reduce
hier netter als loop
. Sie können einfach tun:
Oder, wenn Sie Transienten wirklich mögen:
%Vor%Beide Lösungen durchlaufen die Eingabe nur einmal und sie benötigen viel weniger Code als die loop / recur-Lösung.
Auch andere Lösungen zu den oben genannten netten:
(map (comp count distinct vector) [ 100 2000 ] [ 100 2000 ] [ 101 2001 ] [ 100 2002 ])
Andere geschrieben mit Thread-Last-Makro:
(->> '([100 2000] [100 2000] [101 2001] [100 2002]) (apply map vector) (map distinct) (map count))
beide zurück (2 3).
Tags und Links clojure