Search code examples
c#linq

Continue logic in the LINQ query after anonymous type is created


I currently have a query:

    var query = from x in eksList
        // some joins and other things here ... 
        select new
        {
            Val = x.Something,
            Name = y.OtherThing,                    
        };

And then I do a for-each loop on my query and run some logic based on values on the anonymous object that I got. so for example:

    foreach (var item in query)
    {
        if(SomeMethodCallResult(item.Val))
            myfinalList.Add(item.Name);
        if(SomeOtherLogic(item.Val) > 232)
            myfinalList.Add(item.Name)
    }

So my question is how can I combine this for-each logic into the original LINQ query so first it generates the anonymous result and then runs whatever the logic I am doing in the for-each right after that as part of the LINQ query.

What I tried: I did find the "into" keyword but still not sure how to run logic on that.


Solution

  • This is what I was talking about in my comment. By the way, this is how you prepare a Minimal Reproducible Example.

    First a class:

    public class Eks
    {
        public int Something { get; set; }
        public string? OtherThing { get; set; }
        public string? YetAnother { get; set; }
    }
    

    Then a pair of helpful functions (using the names you proposed).

    public static bool SomeMethodCallResult(int i)
    {
        return i <= 2;
    }
    
    public static int SomeOtherLogic (int i)
    {
        return i + 229;
    }
    

    Then the start of a test function:

    public static void Test()
    {
        var eksList = new List<Eks>
        {
            new Eks { Something = 1, OtherThing = "One", YetAnother = "Still One"},
            new Eks { Something = 2, OtherThing = "Two", YetAnother = "Yup, Two"},
            new Eks { Something = 3, OtherThing = "Three", YetAnother = "Guess it's three"},
            new Eks { Something = 4, OtherThing = "Four", YetAnother = "Four, not for"},
        };
    
        var query = from x in eksList
                        // some joins and other things here ... 
                    select new
                    {
                        Val = x.Something,
                        Name = x.OtherThing,
                    };
        //note, "query" not materialized
    }
    

    Note that this is what you had. At this point, query is an IEnumerable<T> (where T is an anonymous type). I don't need to materialize it right now if I don't want to. I could simply filter it like this:

        var filtered = query.Where(x => SomeMethodCallResult(x.Val) || SomeOtherLogic(x.Val) > 232);
    

    And then I could take the filtered result (still not materialized) and pick out just the names:

        var names = filtered.Select(x => x.Name);
    

    Now I have three unmaterialized collections. I'm not sure what you want to do with them. If you want, say, the original query and the names:

        var queryResult = query.ToList();
        var namesList = names.ToList();
    

    Note that if all you want is the names, then just materialize the names query (only call .ToList on that collection). You aren't creating three lists by going through the original data three times; you are going through the data exactly as many times as you call .ToList().