Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. The Lounge
  3. LINQ "let"

LINQ "let"

Scheduled Pinned Locked Moved The Lounge
36 Posts 16 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Richard DeemingR Richard Deeming

    Shame there's no foreach extension method:

    public static class EnumerableExtensions
    {
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
    {
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (action == null) throw new ArgumentNullException(nameof(action));

        foreach (T item in source)
        {
            action(item);
        }
    }
    

    }

    Then you could do:

    strings.SelectMany(sentence => sentence.Split(' '))
    .Where(word => Array.IndexOf(vowels, char.ToLower(word[0])) != -1)
    .Select(vowelWord => $"\"{vowelWord}\" starts with a vowel")
    .ForEach(Console.WriteLine)
    ;

    :)


    "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

    N Offline
    N Offline
    Nicholas Marty
    wrote on last edited by
    #27

    Well, you could convert the IEnumerable to a List with ToList and call the ForEach method of the List<T> class. Should pretty much equal the foreach loop (as you need to evaluate the query anyways when looping)

    M 1 Reply Last reply
    0
    • N Nicholas Marty

      I think you're mistaking Linq with Linq to SQL. ;-) Depending on the use case you might even gain performance, as an Enumerable is only evaluated when it's needed. As long as you're not accessing the items (or converting it into something other than an IEnumberable with "ToList" or "ToArray") the query isn't evaluated.

      Sander RosselS Offline
      Sander RosselS Offline
      Sander Rossel
      wrote on last edited by
      #28

      Nicholas Marty wrote:

      I think you're mistaking Linq with Linq to SQL. ;-)

      I know the difference very well. I was just assuming we were talking about LINQ to SQL/Entities/whatever data source, because if we're talking LINQ to Objects there really isn't any performance issue to talk about :)

      Read my (free) ebook Object-Oriented Programming in C# Succinctly. Visit my blog at Sander's bits - Writing the code you need. Or read my articles here on CodeProject.

      Simplicity is prerequisite for reliability. — Edsger W. Dijkstra

      Regards, Sander

      N 1 Reply Last reply
      0
      • M Marc Clifton

        Pete O'Hanlon wrote:

        So how have you been solving this in the past? Multiple queries chained together?

        My Linq tends to be rather simple. :)

        Pete O'Hanlon wrote:

        Just wait until you start using "into[^]".

        Though for reporting, yup, been there, done that:

        var categoryRanks = (from gs in geekSkills
        where (gs.ProfileId == profile.Id)
        join s in skills on gs.SkillId equals s.Id
        select new { Level = gs.Level, CategoryId = s.CategoryId } into gss
        join c in categories on gss.CategoryId equals c.Id
        select new { Level = gss.Level, Name = c.Name } into gssc
        group gssc by new { gssc.Name, gssc.Level } into g
        select new SkillLevelBySkillByCategory() {
        SkillLevel = g.Key.Level,
        SkillLevelCount = g.Count(x => x.Level == g.Key.Level),
        Name = g.Key.Name });

        Marc

        Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny

        J Offline
        J Offline
        James Curran
        wrote on last edited by
        #29

        Now, if your table have appropriately assigned foreign keys, then your Profile object would have a "geekSkills" collection of Skills object, which in turn would have a Category property which would have a Name property. Reducing that to :

        var categoryRanks = from s in profile.geekSkills
        group s by new {Level = s.Level, Name = s.Category.Name} into g
        select new SkillLevelBySkillByCategory() { 
        SkillLevel = g.Key.Level, 
        SkillLevelCount = g.Count(x => x.Level == g.Key.Level), 
        Name = g.Key.Name };
        

        Not having the tables (or schema) makes designing that a bit tricky, so that might be off a bit. (like, i"m pretty sure that SkillLevelCount can be just "g.Count()" but I don't know your data) Now, using LET, we can bring that down to :

        var categoryRanks = from s in profile.geekSkills
        let sl = new {Level = s.Level, Name = s.Category.Name}
        group sl by sl into g
        select new SkillLevelBySkillByCategory() {
        SkillLevel = g.Key.Level,
        SkillLevelCount = g.Count(x => x.Level == g.Key.Level),
        Name = g.Key.Name };

        Truth, James

        M 1 Reply Last reply
        0
        • 9 9082365

          You're not missing anything. I trialled Linq functions extensively a couple of years back and they were always slower (sometimes markedly so) than the traditional methods they 'replace'. It all looks very fancy and sophisticated but it's totally inefficient.

          I am not a number. I am a ... no, wait!

          J Offline
          J Offline
          James Curran
          wrote on last edited by
          #30

          Which "traditional" methods? ADO with DataSets? From my experience, LINQ is trivially slower (but with added type-safety benefits to offset it). BUT, linq makes it very easy to write bad queries. Things like, reading an entire table into an array, and then linearly search through it. SO, it you compare a carefully tuned, DBA written stored procedure against a simple query written by a developer with little experience with databases, well, then, LINQ is going to lose. But, it you compare two well-crafted queries, one in LINQ and one in SQL, then you should be nearly the same (since the LINQ will generate the exact same SQL).

          Truth, James

          1 Reply Last reply
          0
          • Sander RosselS Sander Rossel

            Nicholas Marty wrote:

            I think you're mistaking Linq with Linq to SQL. ;-)

            I know the difference very well. I was just assuming we were talking about LINQ to SQL/Entities/whatever data source, because if we're talking LINQ to Objects there really isn't any performance issue to talk about :)

            Read my (free) ebook Object-Oriented Programming in C# Succinctly. Visit my blog at Sander's bits - Writing the code you need. Or read my articles here on CodeProject.

            Simplicity is prerequisite for reliability. — Edsger W. Dijkstra

            Regards, Sander

            N Offline
            N Offline
            Nicholas Marty
            wrote on last edited by
            #31

            Depending on what you're doing with Linq, it can be even faster than a loop – but it can also be slower by more than 100%. If the difference matters is really up to the specific case. I'd guess it doesn't really have a noticeable impact in most cases, as a few milliseconds are negligible.

            1 Reply Last reply
            0
            • M Marc Clifton

              Learned something new today. I was googling for CRC algorithms and came across this nifty site[^] and started perusing it more generally, then realized I had no idea about let clauses in query expressions![^] Geez, I've been using LINQ for a while now, and didn't know about that. :doh: Marc

              Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny

              L Offline
              L Offline
              louthy
              wrote on last edited by
              #32

              For a bit of background. LINQ facilitates functors and monads (concepts from functional programming). Simplified: functors are types that 'map' (Select), monads are types that 'bind' (SelectMany). When you do 'from x in y' you're lifting the value out of the monad (get the value wrapped up *in* the monad), doing an operation on it, and then wrapping it back up in the monad. The monad in this case being IEnumerable/IQueryable. There are other types, like Option, Either, Try - see this library: [language-ext] 'let' is essentially the non-monadic assign, it's essentially exactly the same as declaring a local variable. It doesn't do the lifting, and therefore if you did 'let x = list', then it wouldn't extract the value from the list, it will just assign the list. It's most useful in query expressions to pre-calculate a value that will be used many times in subsequent parts of the query; but it can very much allow full functional programming within LINQ expressions.

              1 Reply Last reply
              0
              • Richard DeemingR Richard Deeming

                Shame there's no foreach extension method:

                public static class EnumerableExtensions
                {
                public static void ForEach<T>(this IEnumerable<T> source, Action<T> action)
                {
                if (source == null) throw new ArgumentNullException(nameof(source));
                if (action == null) throw new ArgumentNullException(nameof(action));

                    foreach (T item in source)
                    {
                        action(item);
                    }
                }
                

                }

                Then you could do:

                strings.SelectMany(sentence => sentence.Split(' '))
                .Where(word => Array.IndexOf(vowels, char.ToLower(word[0])) != -1)
                .Select(vowelWord => $"\"{vowelWord}\" starts with a vowel")
                .ForEach(Console.WriteLine)
                ;

                :)


                "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

                M Offline
                M Offline
                Mark Whybird
                wrote on last edited by
                #33

                I actually thought about a nasty Linq-with-side-effect version with something like

                .Select(vowelWord => Console.WriteLine($"\"{vowelWord}\" starts with a vowel"))

                but of course you can't, because Console.WriteLine() returns Void. No doubt it would be possible to force something like this, but that'd be silly; it's actually quite neat that C# protects us from such folly. For one thing, it won't evaluate until the IEnumerable is enumerated, so you don't really know when that is just from that line of code.

                1 Reply Last reply
                0
                • N Nicholas Marty

                  Well, you could convert the IEnumerable to a List with ToList and call the ForEach method of the List<T> class. Should pretty much equal the foreach loop (as you need to evaluate the query anyways when looping)

                  M Offline
                  M Offline
                  Mark Whybird
                  wrote on last edited by
                  #34

                  Nice.

                  1 Reply Last reply
                  0
                  • J James Curran

                    Now, if your table have appropriately assigned foreign keys, then your Profile object would have a "geekSkills" collection of Skills object, which in turn would have a Category property which would have a Name property. Reducing that to :

                    var categoryRanks = from s in profile.geekSkills
                    group s by new {Level = s.Level, Name = s.Category.Name} into g
                    select new SkillLevelBySkillByCategory() { 
                    SkillLevel = g.Key.Level, 
                    SkillLevelCount = g.Count(x => x.Level == g.Key.Level), 
                    Name = g.Key.Name };
                    

                    Not having the tables (or schema) makes designing that a bit tricky, so that might be off a bit. (like, i"m pretty sure that SkillLevelCount can be just "g.Count()" but I don't know your data) Now, using LET, we can bring that down to :

                    var categoryRanks = from s in profile.geekSkills
                    let sl = new {Level = s.Level, Name = s.Category.Name}
                    group sl by sl into g
                    select new SkillLevelBySkillByCategory() {
                    SkillLevel = g.Key.Level,
                    SkillLevelCount = g.Count(x => x.Level == g.Key.Level),
                    Name = g.Key.Name };

                    Truth, James

                    M Offline
                    M Offline
                    Marc Clifton
                    wrote on last edited by
                    #35

                    James Curran wrote:

                    Now, if your table have appropriately assigned foreign keys,

                    They do, but I haven't set up my models yet with EntityRef and EntitySet. I'll have to do that and then play around with what you're suggesting. I'll be really curious to log what the DataContext does! And thank you for the reductions, that was way beyond the call of duty! Marc

                    Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny

                    J 1 Reply Last reply
                    0
                    • M Marc Clifton

                      James Curran wrote:

                      Now, if your table have appropriately assigned foreign keys,

                      They do, but I haven't set up my models yet with EntityRef and EntitySet. I'll have to do that and then play around with what you're suggesting. I'll be really curious to log what the DataContext does! And thank you for the reductions, that was way beyond the call of duty! Marc

                      Imperative to Functional Programming Succinctly Contributors Wanted for Higher Order Programming Project! Learning to code with python is like learning to swim with those little arm floaties. It gives you undeserved confidence and will eventually drown you. - DangerBunny

                      J Offline
                      J Offline
                      James Curran
                      wrote on last edited by
                      #36

                      Marc Clifton wrote:

                      They do, but I haven't set up my models yet with EntityRef and EntitySet.

                      That shouldn't be necessary. As long as the tables have the foreign keys defined, both Linq2sql & Entity Framework should create the properties automatically.

                      Truth, James

                      1 Reply Last reply
                      0
                      Reply
                      • Reply as topic
                      Log in to reply
                      • Oldest to Newest
                      • Newest to Oldest
                      • Most Votes


                      • Login

                      • Don't have an account? Register

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • World
                      • Users
                      • Groups