2016-04-30 5 views
1

C# Wie erstellt Enumerable.SelectMany mit zwei Funktionsargumenten eine kombinierte Enumerable, basierend auf der msdn-Beschreibung?C# Wie erzeugt Enumerable.SelectMany mit zwei Funktionsargumenten ein kombiniertes Enumerable?

Dies ist kein Duplikat von Difference Between Select and SelectMany Auf dieser Frage und Antworten verwenden viele die SelectMany mit nur einem Funktionsparameter, obwohl ich das verstehe. Und von den zwei Antworten, die SelectMany mit 2 Funktionen verwenden, gibt man nur an, dass es zwei Enumerables kombiniert, es erklärt nicht, wie es das tut. Die msdn-Dokumentation beschreibt keine Kombination von zwei Sammlungen. Es beschreibt einen mechanischeren Prozess und ich kann nicht sehen, wie das, was es beschreibt, zu diesem Ergebnis führt, obwohl ich nicht wirklich verstehe, was msdn für die Funktionalität dieser speziellen Überladung von SelectMany beschreibt.

Ich verstehe den Fall von SelectMany mit einer Funktion. Sie durchläuft jedes Element des Aufzählbaren, ersetzt/transformiert es basierend auf der gegebenen Funktion und verflacht es dann. So

Ich verstehe das

string[] str1 = { "abc", "def", "ghi" }; 
var res = str1.SelectMany(x => "z" + x + "z"); 
foreach (char x in res) Console.Write(x); 
// prints zabczzdefzzghiz 

{"abc","def","ghi"}
wird
{"zabcz","zdefz","zghiz"}
(das ist nach der Funktion Transformation)

Und dann wird es abgeflacht. Jede Zeichenfolge wird zu einem Array von Zeichen abgeflacht und sie werden kombiniert.
{'z','a','b','c','z','z','d','e','f','z','g','h','i','z'}

Wo ich allerdings kämpfen, wenn „Enumerable.SelectMany“ eine zweite Funktion.

Msdn Seite mit einer Liste Überlastungen für Select

https://msdn.microsoft.com/en-us/library/system.linq.enumerable.selectmany(v=vs.100).aspx

Msdn Seite für die Select mit 2 Funktionen

https://msdn.microsoft.com/en-us/library/bb534631(v=vs.100).aspx

So ist die erste Funktion eine collectionSelector, und die zweite Funktion aufgerufen wird, a resultSelector

Diese Beschreibung lesen "P routet jedes Element einer Sequenz zu einem IEnumerable, flacht die resultierenden Sequenzen zu einer Sequenz ab und ruft eine Ergebnisauswahlfunktion für jedes Element darin auf. "

Es klingt von der Beschreibung wie es function1 aufruft, flacht dann das Ergebnis ab und ruft dann function2 auf.

So, jetzt Blick auf ein solches Beispiel

string[] str1 = { "abc", "def", "ghi" }; 
string[] str2 = { "qrs", "tuv", "wxy" }; 

var res = str1.SelectMany(x => str2, (s1, s2) => s1 + s2); 

foreach (string x in res) Console.Write(x+" "); 

//prints abcqrs abctuv abcwxy defqrs deftuv defwxy ghiqrs ghituv ghiwxy 

{ "abc", "def", "ghi" }

nach f1

{ { "qrs", "tuv", "wxy" },{ "qrs", "tuv", "wxy" },{ "qrs", "tuv", "wxy" } }

jetzt wird, wenn ich versuche zu folgen, was ich von der Msdn Beschreibung verstehen, es sagt, das ist abgeflacht.Aber wenn ich es flach dann kann ich sehe keine Möglichkeit, dies

arbeiten können

{ "qrs", "tuv", "wxy" , "qrs", "tuv", "wxy" , "qrs", "tuv", "wxy" }

Wenn auf der anderen Seite ich es nicht flach, so habe ich noch

{ { "qrs", "tuv", "wxy" },{ "qrs", "tuv", "wxy" },{ "qrs", "tuv", "wxy" } }

Dann Ich könnte mir vorstellen, dass vielleicht s1 ein Element des Originals ist, s2 ein Element dieses Intermediates IEnumerable ist. Und es geht in jedes Element der Zwischenstufe, für das erste Element der Zwischenstufe gilt s1 = "abc". Für das zweite Element der Zwischenstufe gilt s1 = "def", für die dritte gilt s1 = "ghi". Und für jede Saite des Zwischen es nicht s1 + s2 und so erhalten Sie

{ { "abcqrs", "abctuv", "abcwxy" },{ "defqrs", "deftuv", "defwxy" },{ "ghiqrs", "ghituv", "ghiwxy" } }

Und dann könnte ich mir vorstellen, dass es es flacht

{ "abcqrs", "abctuv", "abcwxy" , "defqrs", "deftuv", "defwxy" , "ghiqrs", "ghituv", "ghiwxy" }

Und das funktioniert als Erklärung aber Es ist nichts, was MSDN beschreibt.

Msdn beschreibt das Abflachen des Zwischenergebnisses direkt nach der ersten Funktion. Und das verwirrt mich. Ich verstehe nicht, wie es mit der msdn-Beschreibung geht. Obwohl ich die msdn-Beschreibung nicht wirklich verstehe.

Viele nehmen an, dass es zwei IEnumerables kombiniert, aber msdn sagt nicht, dass es das tut, es beschreibt einen Prozess. Und ich würde gerne verstehen, wie dieser Prozess zu zwei IEnumerables führt, die so kombiniert werden, wie sie es tun.

+0

Der .NET-Quellcode kann gelesen werden. Wenn Sie einfach wissen möchten, wie die Methode implementiert wird, finden Sie unter http://referencesource.microsoft.com/#System.Core/System/Linq/Enumerable.cs,bc79a642e00b8681. Wenn Sie mehr wollen, dann ist Ihre Frage viel zu weit gefasst. _ "Obwohl ich die msdn-Beschreibung nicht wirklich verstehe" _ - dann ist es mir ein Rätsel, wie Sie die Richtigkeit der MSDN-Beschreibung in Frage stellen können. –

+0

@PeterDuniho was .. Ich fragte nicht über die Implementierung oder Frage die Richtigkeit der msdn Beschreibung – barlop

+0

obwohl diese Implementierung Link ist sehr hilfreich, ich fragte nicht über Implementierungsdetails – barlop

Antwort

2

Beachten Sie, dass es keine erste f1 und dann f2 gibt. Der ganze Prozess ist so etwas wie eine Pipeline. Es bedeutet:

  1. Geht zum ersten Element ("abc") der Quellensammlung.
  2. Rufen Sie f1 auf und haben Sie die erste Zwischenkollektion ({ "qrs", "tuv", "wxy" }).
  3. Geht zum ersten Element der Zwischenkollektion (qrs), rufen Sie f2 auf.
  4. Ausbeute das erste Ergebnis, abcqrs.
  5. Geht zu Schritt 3, bis kein Element in der ersten Zwischensammlung vorhanden ist.
  6. ...

So gibt es keine Zwischen Sammlung mit Elementen { { "qrs", "tuv", "wxy" },{ "qrs", "tuv", "wxy" },{ "qrs", "tuv", "wxy" } }. Das Ergebnis ist eins nach dem anderen.

Die MSDN Beschreibung verwirrt Menschen. Es klingt wie ein Zwischenschritt der Methode. Tatsächlich wird das flatten Verhalten durchgeführt, wenn Sie das Ergebnis iterieren.

von barlop hinzugefügt

der .NET-Implementierung Code Peter erwähnt ist in diesem Fall sehr hilfreich sein. (Beachten Sie, ich habe einige unnötige Klammern aus Gründen der Ordnung entfernt). Es bestätigt, was oben geschrieben ist.

static IEnumerable<TResult> SelectManyIterator<TSource, TCollection, TResult>(IEnumerable<TSource> source, Func<TSource, IEnumerable<TCollection>> collectionSelector, Func<TSource, TCollection, TResult> resultSelector) 
    { 
     foreach (TSource element in source) 
      foreach (TCollection subElement in collectionSelector(element))        
       yield return resultSelector(element, subElement); 
    } 
+0

so Schritt 6 wird abgeflacht – barlop

Verwandte Themen