Ich habe eine IEnumerable<T>
und eine IEnumerable<U>
, die ich in eine IEnumerable<KeyValuePair<T,U>>
zusammengeführt werden soll, wo die Indizes der Elemente in KeyValuePair zusammengefügt sind die gleichen. Hinweis: Ich verwende nicht IList, daher habe ich keine Zählung oder einen Index für die Elemente, die ich zusammenführe. Wie kann ich das am besten erreichen? Ich würde eine LINQ-Antwort bevorzugen, aber alles, was die Arbeit in einer eleganten Art und Weise erledigt, würde auch funktionieren.Wie kann ich zwei IEnumerables zusammenführen (oder zippen)?
Antwort
Hinweis: Ab .NET 4.0, das Framework eine .Zip
Erweiterung umfasst Verfahren auf IEnumerable, dokumentiert here. Folgendes wird für die Nachwelt und für die Verwendung in der .NET-Framework-Version vor 4.0 beibehalten.
Ich benutze diese Erweiterungsmethoden:
// From http://community.bartdesmet.net/blogs/bart/archive/2008/11/03/c-4-0-feature-focus-part-3-intermezzo-linq-s-new-zip-operator.aspx
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> func) {
if (first == null)
throw new ArgumentNullException("first");
if (second == null)
throw new ArgumentNullException("second");
if (func == null)
throw new ArgumentNullException("func");
using (var ie1 = first.GetEnumerator())
using (var ie2 = second.GetEnumerator())
while (ie1.MoveNext() && ie2.MoveNext())
yield return func(ie1.Current, ie2.Current);
}
public static IEnumerable<KeyValuePair<T, R>> Zip<T, R>(this IEnumerable<T> first, IEnumerable<R> second) {
return first.Zip(second, (f, s) => new KeyValuePair<T, R>(f, s));
}
EDIT: Nach den Kommentaren Ich bin verpflichtet, einige Dinge zu klären und zu beheben:
- Ich habe ursprünglich die erste Zip Implementierung wörtlich aus Bart De Smet's blog
- Hinzugefügt Enumerator Entsorgung (die auch noted auf Bart ursprünglichen Post) war
- hinzugefügt Null-Parameterprüfung (auch in Bart Beitrag diskutiert)
Schöner als meine. – erikkallen
Das ist falsch, da IEnumerables die Reihenfolge beibehalten. – Welbog
Sortieren: es ermutigt den _caller_, die Annahme zu machen. Dies ist das einzige, was es tun kann, und manchmal ist die Annahme begründet. –
Überlegen Sie, was Sie mehr ein bisschen eng hier sind gefragt:
Sie zwei IEnumerables kombinieren möchten, in denen „die Indizes der Elemente zusammen in der KeyValuePair verbunden sind gleich“, aber sie " haben keine Zählung oderIndex für die Elemente, die ich fusioniere ".
Es gibt keine Garantie, dass Ihre IEnumerables sogar sortiert oder unsortiert sind. Es gibt keine Korrelation zwischen Ihren beiden IEnumerable-Objekten. Wie können Sie also erwarten, dass sie korrelieren?
@welbog: Es sieht so aus, als gäbe es ein Missverständnis der Frage. Ich denke, dass "Erik" mit "Index" die Position des Elements in der IEnumerable (1., 2., etc.) bedeutete –
@mausch: eine Position, die nicht garantiert ist. Abhängig von der Implementierung ist die Reihenfolge der beiden IEnumerables möglicherweise nicht so wie erwartet. – Welbog
@welbog: Wäre es sinnvoll, Zip mit einem solchen Enumerable aufzurufen? Entweder ergibt das keinen Sinn oder der Anrufer muss sich dessen bewusst sein ... Ich sehe keine andere Option. –
Ungeprüfte, aber funktionieren soll:
IEnumerable<KeyValuePair<T, U>> Zip<T, U>(IEnumerable<T> t, IEnumerable<U> u) {
IEnumerator<T> et = t.GetEnumerator();
IEnumerator<U> eu = u.GetEnumerator();
for (;;) {
bool bt = et.MoveNext();
bool bu = eu.MoveNext();
if (bt != bu)
throw new ArgumentException("Different number of elements in t and u");
if (!bt)
break;
yield return new KeyValuePair<T, U>(et.Current, eu.Current);
}
}
Blick auf nextension:
Derzeit implementierten Methoden
IEnumerable
- ForEach Führt eine angegebene Aktion für jedes Element des IEnumerable.
- Clump Gruppiert Elemente in gleiche Größe.
- Scan Erstellt eine Liste, indem ein Delegat auf Elementpaare in IEnumerable angewendet wird.
- AtLeast Checks gibt es mindestens eine bestimmte Anzahl von Elementen im IEnumerable.
- AtMost Checks Es gibt nicht mehr als eine bestimmte Anzahl von Elementen im IEnumerable.
- Zip Erstellt eine Liste, indem zwei andere Listen zu einer zusammengefasst werden.
- Zyklus Erstellt eine Liste durch Wiederholung einer anderen Liste.
Die MSDN hat folgende Custom Sequence Operators Beispiel. Und Welbog hat recht; Wenn Sie keinen Index zu den zugrunde liegenden Daten haben, können Sie nicht garantieren, dass der Vorgang das tut, was Sie erwarten.
würde ich etwas entlang der Linien von verwenden -
IEnumerable<KeyValuePair<T,U>> Merge<T,U>(IEnumerable<T> keyCollection, IEnumerable<U> valueCollection)
{
var keys = keyCollection.GetEnumerator();
var values = valueCollection.GetEnumerator();
try
{
keys.Reset();
values.Reset();
while (keys.MoveNext() && values.MoveNext())
{
yield return new KeyValuePair<T,U>(keys.Current,values.Current);
}
}
finally
{
keys.Dispose();
values.Dispose();
}
}
Dies sollte richtig danach richtig und Aufräumarbeiten.
Ich denke, es ist eine gute Form, es "Zip" zu nennen, denn das ist eine bekannte Operation in der funktionalen Welt. – Daniel
Eine weitere Implementierung der functional-dotnet project von Alexey Romanov:
/// <summary>
/// Takes two sequences and returns a sequence of corresponding pairs.
/// If one sequence is short, excess elements of the longer sequence are discarded.
/// </summary>
/// <typeparam name="T1">The type of the 1.</typeparam>
/// <typeparam name="T2">The type of the 2.</typeparam>
/// <param name="sequence1">The first sequence.</param>
/// <param name="sequence2">The second sequence.</param>
/// <returns></returns>
public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(
this IEnumerable<T1> sequence1, IEnumerable<T2> sequence2) {
using (
IEnumerator<T1> enumerator1 = sequence1.GetEnumerator())
using (
IEnumerator<T2> enumerator2 = sequence2.GetEnumerator()) {
while (enumerator1.MoveNext() && enumerator2.MoveNext()) {
yield return
Pair.New(enumerator1.Current, enumerator2.Current);
}
}
//
//zip :: [a] -> [b] -> [(a,b)]
//zip (a:as) (b:bs) = (a,b) : zip as bs
//zip _ _ = []
}
ersetzen Pair.New
mit neuen KeyValuePair<T1, T2>
(und dem Rückgabetyp), und Sie sind gut zu gehen.
Als Update jemand über diese Frage zu stolpern, .Net 4.0 unterstützt diese nativ als ex von MS:
int[] numbers = { 1, 2, 3, 4 };
string[] words = { "one", "two", "three" };
var numbersAndWords = numbers.Zip(words, (first, second) => first + " " + second);
- 1. Wie kann ich zwei JavaScript-Objekte zusammenführen?
- 2. Wie kann ich zwei Arrays in JavaScript zippen?
- 3. Wie kann ich mehr als zwei Iteratoren zippen?
- 4. Wie kann ich zwei JObject zusammenführen?
- 5. Wie kann ich zwei MySQL-Tabellen zusammenführen?
- 6. Wie kann ich mehrere IEnumerables von T
- 7. Kann ich das Delta von zwei IEnumerables in LINQ erhalten?
- 8. Wie kann ich zwei Verzeichnisse mit opendiff zusammenführen?
- 9. Assert IEnumerables
- 10. Wie Zip verwenden, um auf drei IEnumerables
- 11. Wie kann ich zwei MySQL-Datenbanken mit identischem Schema zusammenführen?
- 12. C#: Inhalt von zwei IEnumerables vergleichen
- 13. Wie man die Verkettung von IEnumerables von IEnumerables
- 14. Wie kann ich zwei Dateien in einem mit BASH oder Python-Skript zusammenführen?
- 15. Wie zwei eloquente Sammlungen zusammenführen?
- 16. Wie kann ich PHP-Arrays zusammenführen?
- 17. zwei Datenbanken zusammenführen
- 18. Wie kann ich Zweige auf Github zusammenführen
- 19. Wie kann ich einen Ordner in Grunt zippen?
- 20. Wie bestimmt Assert.AreEqual die Gleichheit zwischen zwei generischen IEnumerables?
- 21. zwei Prioritätswarteschlangen zusammenführen
- 22. Zwei Ströme zusammenführen
- 23. Wie kann ich TypedArrays in JavaScript zusammenführen?
- 24. Kann zwei Wörterbücher in Python nicht zusammenführen
- 25. Zwei Bindungseigenschaften zusammenführen?
- 26. Wie kann ich Jinja2-Wörterbücher ändern/zusammenführen?
- 27. Groovy zwei Listen zusammenführen?
- 28. Zusammenführen von zwei PropertyInfo
- 29. Zwei Hashes zusammenführen
- 30. Unterschiede/Zusammenführen von zwei Dateien
Ab .NET 4.0, kommt der Rahmen mit einem [IEnumerable Zip] (http://msdn.microsoft.com/en-us/library/dd267698%28v=vs.110%29.aspx) Erweiterungsmethode. –
Immer noch [ein anderer Blogbeitrag] (http://blogs.msdn.com/ericlippert/archive/2009/05/07/zip-me-up.aspx) von Eric Lippert – n8wrl
Lustig - Ich habe gerade diese letzte Nacht gelesen. =) –