Gibt es eine gute Möglichkeit, eine Sammlung n
mit LINQ in Teile zu teilen ? Natürlich nicht unbedingt gleichmäßig.
Das heißt, ich möchte die Sammlung in Untersammlungen unterteilen, die jeweils eine Teilmenge der Elemente enthalten, in denen die letzte Sammlung zerlumpt werden kann.
c#
.net
linq
data-structures
Simon_Weaver
quelle
quelle
Antworten:
Eine reine Linq und die einfachste Lösung ist wie unten gezeigt.
quelle
.AsEnumerable()
ist nicht erforderlich, IGrouping <T> ist bereits eine IEnumerable <T>.EDIT: Okay, es sieht so aus, als hätte ich die Frage falsch verstanden. Ich las es als "Stücke der Länge n" und nicht als "n Stücke". Doh! Erwägen, die Antwort zu löschen ...
(Ursprüngliche Antwort)
Ich glaube nicht, dass es eine integrierte Partitionierungsmethode gibt, obwohl ich beabsichtige, eine in meine Reihe von Ergänzungen zu LINQ to Objects zu schreiben. Marc Gravell hat hier eine Implementierung, obwohl ich sie wahrscheinlich ändern würde, um eine schreibgeschützte Ansicht zurückzugeben:
quelle
yield return
. Es muss jeweils ein Stapel gespeichert sein, aber das ist alles.quelle
var dept = {1,2,3,4,5}
. Nach dem Teilen ist das Ergebnis wiedept1 = {1,3,5}
unddept2 = { 2,4 }
woparts = 2
. Aber das Ergebnis, das ich brauche, istdept1 = {1,2,3}
unddept2 = {4,5}
int columnLength = (int)Math.Ceiling((decimal)(list.Count()) / parts);
dann mit geteilt.GroupBy(x => x.index / columnLength)
. Ein Nachteil ist, dass Count () die Liste auflistet.Ok, ich werfe meinen Hut in den Ring. Die Vorteile meines Algorithmus:
Der Code:
Wie in den Kommentaren unten ausgeführt, geht dieser Ansatz nicht auf die ursprüngliche Frage ein, bei der eine feste Anzahl von Abschnitten mit ungefähr gleicher Länge gefordert wurde. Trotzdem können Sie meinen Ansatz immer noch verwenden, um die ursprüngliche Frage zu lösen, indem Sie sie so nennen:
Bei dieser Verwendung ist der Ansatz nicht mehr O (1), da die Count () -Operation O (N) ist.
quelle
Dies ist das Gleiche wie die akzeptierte Antwort, jedoch eine viel einfachere Darstellung:
Das obige Verfahren teilt eine
IEnumerable<T>
in N Anzahl von Blöcken gleicher Größe oder nahezu gleicher Größe auf.Bei der obigen Methode wird ein
IEnumerable<T>
in Blöcke mit der gewünschten festen Größe aufgeteilt, wobei die Gesamtzahl der Blöcke unwichtig ist - worum es bei der Frage nicht geht.Das Problem bei der
Split
Methode ist, dass sie nicht nur langsamer ist, sondern auch die Ausgabe in dem Sinne verschlüsselt, dass die Gruppierung auf der Grundlage des i-ten Vielfachen von N für jede Position erfolgt, oder mit anderen Worten, Sie erhalten die Chunks nicht in der ursprünglichen Reihenfolge.Fast jede Antwort hier bewahrt entweder nicht die Ordnung oder handelt von Partitionierung und nicht von Aufteilung oder ist eindeutig falsch. Versuchen Sie dies, was schneller ist, die Ordnung bewahrt, aber ein bisschen ausführlicher ist:
Die äquivalente Methode für eine
Partition
Operation hierquelle
Ich habe die Partitionsfunktion, die ich zuvor gepostet habe, ziemlich oft verwendet. Das einzig schlechte daran war, dass es nicht vollständig gestreamt wurde. Dies ist kein Problem, wenn Sie mit wenigen Elementen in Ihrer Sequenz arbeiten. Ich brauchte eine neue Lösung, als ich anfing, mit mehr als 100.000 Elementen in meiner Sequenz zu arbeiten.
Die folgende Lösung ist viel komplexer (und mehr Code!), Aber sehr effizient.
Genießen!
quelle
Interessanter Thread. Um eine Streaming-Version von Split / Partition zu erhalten, können Enumeratoren verwendet und mithilfe von Erweiterungsmethoden Sequenzen aus dem Enumerator ausgegeben werden. Das Konvertieren von imperativem Code in funktionalen Code unter Verwendung von Yield ist in der Tat eine sehr leistungsfähige Technik.
Zuerst eine Enumerator-Erweiterung, die eine Anzahl von Elementen in eine verzögerte Sequenz verwandelt:
Und dann eine aufzählbare Erweiterung, die eine Sequenz partitioniert:
Das Endergebnis ist eine hocheffiziente, Streaming- und Lazy-Implementierung, die auf sehr einfachem Code basiert.
Genießen!
quelle
Ich benutze das:
quelle
Dies ist speichereffizient und verzögert die Ausführung so weit wie möglich (pro Stapel) und arbeitet in der linearen Zeit O (n).
quelle
Es gibt viele gute Antworten auf diese Frage (und ihre Cousins). Ich brauchte dies selbst und hatte eine Lösung entwickelt, die effizient und fehlertolerant in einem Szenario ist, in dem die Quellensammlung als Liste behandelt werden kann. Es wird keine verzögerte Iteration verwendet, daher ist es möglicherweise nicht für Sammlungen unbekannter Größe geeignet, die möglicherweise Speicherdruck ausüben.
Ich habe einige Antworten in dieser Familie von Fragen gesehen, die GetRange und Math.Min verwenden. Insgesamt glaube ich jedoch, dass dies eine vollständigere Lösung in Bezug auf Fehlerprüfung und Effizienz ist.
quelle
quelle
Tolle Antworten, für mein Szenario habe ich die akzeptierte Antwort getestet und es scheint, dass sie nicht in Ordnung bleibt. Es gibt auch eine großartige Antwort von Nawfal, die Ordnung hält. Aber in meinem Szenario wollte ich den Rest auf normalisierte Weise aufteilen. Alle Antworten, die ich sah, verteilten den Rest oder am Anfang oder am Ende.
Meine Antwort geht auch davon aus, dass sich der Rest normalisiert.
quelle
Wenn die Reihenfolge in diesen Teilen nicht sehr wichtig ist, können Sie Folgendes versuchen:
Diese können jedoch aus irgendeinem Grund nicht in IEnumerable <IEnumerable <int>> umgewandelt werden ...
quelle
Das ist mein Code, nett und kurz.
quelle
Dies ist meine Art, Elemente aufzulisten und Zeilen für Spalten aufzuteilen
quelle
Ich habe nach einem Split wie dem mit String gesucht, daher wird die gesamte Liste nach einer Regel aufgeteilt, nicht nur nach dem ersten Teil, dies ist meine Lösung
quelle
Hier ist eine kleine Änderung für die Anzahl der Elemente anstelle der Anzahl der Teile:
quelle
quelle
Ich bin gerade auf diesen Thread gestoßen, und die meisten Lösungen hier umfassen das Hinzufügen von Elementen zu Sammlungen, wodurch jede Seite effektiv materialisiert wird, bevor sie zurückgegeben wird. Dies ist aus zwei Gründen schlecht: Erstens, wenn Ihre Seiten groß sind, entsteht ein Speicheraufwand für das Füllen der Seite, zweitens gibt es Iteratoren, die frühere Datensätze ungültig machen, wenn Sie zum nächsten übergehen (z. B. wenn Sie einen DataReader in eine Enumerator-Methode einschließen). .
Diese Lösung verwendet zwei verschachtelte Enumerator-Methoden, um zu vermeiden, dass Elemente in temporären Sammlungen zwischengespeichert werden müssen. Da der äußere und der innere Iterator dieselbe Aufzählung durchlaufen, teilen sie sich notwendigerweise denselben Aufzähler. Daher ist es wichtig, den äußeren nicht vorzurücken, bis Sie mit der Verarbeitung der aktuellen Seite fertig sind. Wenn Sie sich jedoch dazu entschließen, die aktuelle Seite nicht vollständig zu durchlaufen, wird diese Lösung beim Wechseln zur nächsten Seite automatisch zur Seitengrenze weitergeleitet.
quelle