2017-02-11 3 views
3

Ich bin ziemlich neu in der Programmierung und ich habe herum mit dem Schreiben einige zufällige Funktionen gespielt.IEnumerable Elemente verschwinden vor der Verwendung mit LINQ Wo

Ich schrieb die unten stehende Funktion, die lose auf Eratosthenes Sieb basiert. Anfangs hatte ich ein Problem mit IEnumerable updatedEntries.

Die updatedEntites wurde Art bevölkern (etwas mit verzögerter Ausführung zu tun, ich sammeln - im Debug-Modus der ‚aktuellen‘ war null, aber die Ergebnisse Ansicht die entsprechenden Positionen enthalten), aber wenn die RemoveWhere die Elemente in updatedEntries auf oddPrimesAndMultiples angewendet wurde verschwunden, obwohl ich nicht sehe, warum sie immer noch mit den Elementen in oddPrimesAndMultiples verknüpft werden sollten. (Ich könnte einfach völlig falsch verstehen, was läuft natürlich und das Problem könnte etwas ganz anderes sein!)

Das Problem tritt nicht auf, wenn ich updatedEntries zu einer Liste statt IEnumerable ändern und ich habe jetzt neu geschrieben Diese Aussage, ohne LINQ zu benutzen (potentiell?), macht die Tatsache, dass ich ein SortedSet verwende, besser aus ... aber ich würde trotzdem gerne wissen, warum das Problem überhaupt aufgetreten ist!

Hier ist mein Code:

public static IEnumerable<int> QuickPrimes() 
     { 
      int firstPrime = 2; 
      int firstOddPrime = 3; 

      int currentValue = firstOddPrime; 
      int currentMinimumMultiple; 

      SortedSet<Tuple<int, int>> oddPrimesAndMultiples = new SortedSet<Tuple<int, int>>() { new Tuple<int, int> (firstOddPrime, firstOddPrime) }; 
      IEnumerable<Tuple<int, int>> updatedEntries; 

      yield return firstPrime; 
      yield return firstOddPrime; 

      while (true) 
      { 
       currentMinimumMultiple = oddPrimesAndMultiples.First().Item1; 
       while (currentValue < currentMinimumMultiple) 
       { 
        yield return currentValue; 
        oddPrimesAndMultiples.Add(new Tuple<int, int> (currentValue * 3, currentValue)); 
        currentValue += 2; 
       } 

       updatedEntries = oddPrimesAndMultiples.Where(tuple => tuple.Item1 == currentMinimumMultiple) 
                 .Select(t => new Tuple<int, int>(t.Item1 + 2 * t.Item2, t.Item2)); 

       oddPrimesAndMultiples.RemoveWhere(t => t.Item1 == currentMinimumMultiple); 
       oddPrimesAndMultiples.UnionWith(updatedEntries); 
       currentValue += 2; 
      } 
     } 

und die Haupt, wo ich die Funktion bin Tests:

static void Main(string[] args) 
     { 
      foreach(int prime in Problems.QuickPrimes()) 
      { 
       Console.WriteLine(prime); 
       if (prime > 20) return; 
      } 
     } 

Vielen Dank im Voraus!

+0

Ein IEnumerable, das das Schlüsselwort yield verwendet, kann tatsächlich sehr unterschiedliche Ergebnisse liefern. Benutze es weise. –

+0

Lassen Sie mich sehen, wenn ich das verstehe, funktioniert Ihr Code jetzt wie dargestellt funktioniert, aber zuvor war es nicht, weil Sie nicht den Aufruf ".ToList()" auf die Zuweisung von updatedEntries, richtig? –

+0

Könnten Sie bitte [MCVE] des Problems angeben? Mit der aktuellen Post ist es noch nicht einmal klar, ob Code das Thema hat, über das du redest oder nicht. –

Antwort

1

Die Falle ist, dass updatedEntries in einer Zeile definiert ist, aber tatsächlich später ausgeführt.

es um die Grundlagen finden Sie in diesem Code-Schnipsel zurückbringen (von LINQPad):

var ints = new SortedSet<int>(new[] { 1,2,3,4,5,6,7,8,9,10}); 

var updatedEntries = ints.Where(i => i > 5); // No ToList()! 
updatedEntries.Dump(); 

Dies zeigt 6, 7, 8, 9, 10.

ints.RemoveWhere(i => i > 7); 
updatedEntries.Dump(); 

Nun zeigt diese 6, 7, weil updatedEntries erneut ausgeführt.

ints.UnionWith(updatedEntries); 

Dies fügt 6, 7, während Sie es erwartet 6, 7, 8, 9, 10 die erste Liste hinzufügen.

Wenn Sie also eine IEnumerable definieren, sollten Sie immer wissen, wann sie tatsächlich ausgeführt wird. Es wirkt immer auf den Zustand des Programms an diesem bestimmten Punkt.

Verwandte Themen