2

I just started learning lambda/linq. Here's what I have so far.

var frequency = from f in "trreill".ToList()
                group f by f into letterfrequency
                select letterfrequency;

foreach (var f in frequency)
{
    Console.WriteLine($"{f.Key}{f.Count()}");
}

Here is the output:

t1 r2 e1 i1 l2

Output needed:

e1i1l2r2t1

Can't figure out how to sort properly. Any thoughts to what I'm doing wrong?

Dayan
  • 7,634
  • 11
  • 49
  • 76
MBrewers
  • 141
  • 10
  • 1
    `frequency = frequency.OrderBy(x => x.Count);` – Ryan Wilson Nov 20 '18 at 14:58
  • You simply want to order by `letterfrequency.Key`, then by `letterfrequency.Count()`? Given your grouping, the latter will not matter. – CodeCaster Nov 20 '18 at 14:59
  • 5
    Can you explain why you wrote an unnecessary `ToList` in there? I am interested to learn why people write unnecessary code because it helps me design APIs that lead developers to avoid writing unnecessary code. – Eric Lippert Nov 20 '18 at 15:04
  • By "followed by" do you mean print out the key and then follow it by the count? Or do you mean that the ordering relation depends on the count? If the latter, how does that ever make a difference? – Eric Lippert Nov 20 '18 at 15:08
  • @EricLippert It perplexed me that no one addressed the `ToList()` in their answers, I am glad to see some sanity in the comments – maccettura Nov 20 '18 at 15:13
  • 1
    The ToList() was one of the ways I was trying sort, originally, because I couldn't get it to work properly. I know, bad coding but I'm trying:) Many thanks – MBrewers Nov 20 '18 at 15:53

3 Answers3

6

The thing you're missing is adding an orderby to your LINQ statement:

var frequency = from f in "trreill"
                group f by f into letterfrequency
                orderby letterfrequency.Key
                select new
                {
                    Letter = letterfrequency.Key,
                    Frequency = letterfrequency.Count()
                };

foreach (var f in frequency)
{
    Console.WriteLine($"{f.Letter}{f.Frequency}");
}

The letterfrequency has a property called Key which contains the letter for each group, so adding orderby letterfrequency.Key sorts the results to give you the output you're after:

e1

i1

l2

r2

t1

I've also tweaked the result of the query slightly (simply to show that it's something that's possible) to generate a new anonymous type that contains the Letter and the Frequency as named properties. This makes the code in the Console.WriteLine a littl clearer as the properties being used are called Letter and Frequency rather than Key and the Count() method.

Turning it up to 11, using C# 7.0 Tuples

If you're using C# 7.0, you could replace the use of an anonymous type with Tuples, that means that the code would now look like this:

var frequency = from f in "trreill"
                group f by f into letterfrequency
                orderby letterfrequency.Key
                select
                (
                    Letter: letterfrequency.Key,
                    Frequency: letterfrequency.Count()
                );


foreach (var (Letter, Frequency) in frequency)
{
    Console.WriteLine($"{Letter}{Frequency}");
}

I've blogged about this, and there are plenty of other resources that describe them, including this Stackoverflow question that asks 'Are C# anonymous types redundant in C# 7', if you want a deeper dive into Tuples, what they are, how they work and why/when you might want to use them in preference to anonymous types.

Rob
  • 45,296
  • 24
  • 122
  • 150
2

Just sort your list as following:

        foreach (var f in frequency.OrderBy(item=>item.Key))
        {
            Console.WriteLine($"{f.Key}{f.Count()}");
        }
Ehsan.Saradar
  • 664
  • 6
  • 10
1

I would select into an anonymous object:

var frequency = from f in "trreill"
                     group f by f into letterfrequency
                     select new { Key = letterfrequency.Key, Count = letterfrequency.Count() };

Then I would order it like so:

foreach (var f in frequency.OrderBy(x => x.Key))
{
    Console.WriteLine($"{f.Key}{f.Count}");
}