Wordt het aantal invoerelementen hetzelfde behandeld, ongeacht wanneer de operator Linq-to-Objects wordt gebeld?

Hoewel de operator Selecteer wordt aangeroepen vóór de operator Take , wordt de lambda-expressie alleen aangeroepen voor de eerste twee invoerelementen:

        string[] count = { "one ", "two ", "three ", "four ", "five ", "six " };
        IEnumerable results = count.Select(item =>
                               {
                                      Console.WriteLine(item);
                                      return item.Length;
                               }).Take(2); 
        foreach (int i in results);

OUTPUT:

one two 

a) Aangenomen dat we meerdere standaard-queryoperatoren van Linq-to-Objects aan elkaar koppelen, is de volgorde waarin de operator Take wordt aangeroepen nooit belangrijk? Het maakt dus nooit uit of Take als eerste of als laatste wordt aangeroepen, omdat het aantal invoerelementen waarvoor de lambda-expressie wordt aangeroepen, altijd hetzelfde is?

b) Nogmaals, ervan uitgaande dat we meerdere standaard-queryoperatoren van Linq-to-Objects aan elkaar koppelen, zijn er andere Linq-to-Objects-operatoren waar de volgorde waarin ze worden aangeroepen geen invloed heeft op het aantal invoerelementen waarvoor de lambda-expressie wordt opgehaald genoemd?

Dank je

0

2 antwoord

Bestelling is belangrijk, maar de uitvoering wordt meestal uitgesteld en ongetwijfeld geoptimaliseerd. Als uw beweringen/waarnemingen juist waren, zou het toevoegen van een ToList() vóór Take() geen invloed hebben op de uitvoer, maar dat doet het wel. De ToList() -aanroep werkt om volledige opsomming voorafgaand aan de Take() te forceren en resulteert erin dat de Select lambda op alle elementen wordt aangeroepen.

De les hier is niet afhankelijk zijn van optimalisaties voor de juistheid.

string[] count = { "one ", "two ", "three ", "four ", "five ", "six " }; 
IEnumerable results = count.Select(item => 
                           { 
                                      Console.WriteLine(item); 
                                      return item.Length; 
                           })
                          .ToList()
                          .Take(2);
1
toegevoegd
@AspOnMyNet - sorry, ik had moeten aangeven dat het zou worden toegevoegd tussen de Select en Take. Bijgewerkt.
toegevoegd de auteur tvanfosson, de bron
"Als uw beweringen/waarnemingen juist waren, zou het toevoegen van een ToList() geen effect hebben op de uitvoer, maar het doet" Ik weet niet helemaal zeker wat u zegt, sinds het aanroepen van count.Select (item => {Console. WriteLine (item); return item.Length;}). Take (2) .ToList (); geeft me dezelfde output. Met andere woorden, lambda-expressie wordt alleen aangeroepen voor de eerste twee elementen
toegevoegd de auteur AspOnMyNet, de bron
dank voor uw toelichting
toegevoegd de auteur AspOnMyNet, de bron

Query-operators verplaatsen meestal maar zo veel stappen naar voren in de bronverzameling als ze nodig hebben om het aantal vereiste uitvoerresultaten te produceren.

In uw voorbeeld Take() vereist slechts 2 items van Selecteer() , dus dat is alles wat wordt geproduceerd door Selecteer() . Select() is waarschijnlijk ongeveer zoals deze geïmplementeerd (overgenomen van blog van Jon Skeet :

private static IEnumerable<tresult> Select( 
    this IEnumerable source, 
    Func selector) 
{ 
    foreach (TSource item in source) 
    { 
        yield return selector(item); 
    } 
}

Operators sorteren en groeperen moeten de volledige resultaatset maken voordat ze iets kunnen retourneren (bijvoorbeeld OrderBy() ).

Zolang u geen ordening, groepering of filtering gebruikt (zoals met Waar() of Overslaan() ) of een andere operator die het aantal items in in de volgorde maakt het niet uit waar je in de keten de Take() plaatst.

1
toegevoegd
De volgorde van Take is altijd belangrijk in relatie tot Overslaan .
toegevoegd de auteur Andrew Barber, de bron
@AndrewBarber: Je hebt gelijk, dat is een ander filter dat ik heb gemist. Ik heb het opgehelderd.
toegevoegd de auteur Anders Abel, de bron
1) Als u de reeks {3, 7, 2, 4} Take (2) hebt. OrderBy (i => i) produceert {3, 7} terwijl OrderBy (i => i). Take (2) produceert {2, 4} wat nogal verschilt. 2) Weet het niet. Ik denk dat de conclusie is dat je nooit, nooit bijwerkingen zult hebben in de functies/lambda's die met linq worden gebruikt.
toegevoegd de auteur Anders Abel, de bron
Een neveneffect is dat de lambda iets anders doen dan alleen een waarde teruggeven op basis van de invoer, zoals het aanroepen van Console.WriteLine . Het is interessant om te leren, maar doe het nooit in echte code.
toegevoegd de auteur Anders Abel, de bron
@Anders: 1) "Operators sorteren en groeperen moeten de volledige resultaatset maken voordat ze iets kunnen retourneren (bijvoorbeeld OrderBy ())." Wat OrderBy en Take goes betreft, neem ik aan dat in de keten Take is called alleen het aantal invoerelementen wordt beïnvloed dat wordt verwerkt, maar de resulterende sequentie is altijd in dezelfde volgorde? 2) Zijn er andere operatoren waar (onder de juiste omstandigheden - zoals geen groepering en geen bestelling) de volgorde waarin ze worden genoemd niet belangrijk is?
toegevoegd de auteur AspOnMyNet, de bron
2) Wat bedoel je met "nooit bijwerkingen hebben"? Misschien dat ik altijd moet aannemen dat de volgorde van operatoren bijwerkingen heeft?
toegevoegd de auteur AspOnMyNet, de bron
bedankt allemaal voor je hulp
toegevoegd de auteur AspOnMyNet, de bron