Best linq questions in July 2011

What function acts as .SelectMany() in jQuery?

13 votes

Let me explain more:

we know that map function in jQuery acts as .Select() (as in LINQ).

$("tr").map(function() { return $(this).children().first(); }); // returns 20 tds

now the question is how can we have .SelectMany() in jQuery?

$("tr").map(function() { return $(this).children(); }); // returns 10 arrays not 20 tds!

here is my example in action: http://jsfiddle.net/8aLFQ/4/
"l2" should be 8 if we have selectMany.

[NOTE] please don't stick to this example, above code is to just show what I mean by SelectMany() otherwise it's very easy to say $("tr").children();

Hope it's clear enough.

map will flatten native arrays. Therefore, you can write:

$("tr").map(function() { return $(this).children().get(); })

You need to call .get() to return a native array rather than a jQuery object.

Summing the previous values in an IEnumerable

10 votes

I have a sequence of numbers:

var seq = new List<int> { 1, 3, 12, 19, 33 };

and I want to transform that into a new sequence where the number is added to the preceding numbers to create a new sequence:

{ 1, 3, 12, 19, 33 } --> {1, 4, 16, 35, 68 }

I came up with the following, but I dislike the state variable 'count'. I also dislike the fact that I'm using the values Enumerable without acting on it.

int count = 1;
var summed = values.Select(_ => values.Take(count++).Sum());

How else could it be done?

As I showed in my comment, this is a common pattern in functional programming which in F# is called scan. It's like C#'s Enumerable.Aggregate and F#'s fold except that it yields the intermediate results of the accumulator along with the final result. We can implement scan in C# nicely with an extension method:

public static IEnumerable<U> Scan<T, U>(this IEnumerable<T> input, Func<U, T, U> next, U state) {
    yield return state;
    foreach(var item in input) {
        state = next(state, item);
        yield return state;
    }
}

And then use it as follows:

var seq = new List<int> { 1, 3, 12, 19, 33 };
var transformed = seq.Scan(((state, item) => state + item), 0).Skip(1);

VB.NET linq group by with anonymous types not working as expected

6 votes

I was toying around with some of the linq samples that come with LINQPad. In the "C# 3.0 in a Nutshell" folder, under Chater 9 - Grouping, there is a sample query called "Grouping by Multiple Keys". It contains the following query:

from n in new[] { "Tom", "Dick", "Harry", "Mary", "Jay" }.AsQueryable()
group n by new
{
    FirstLetter = n[0],
    Length = n.Length
}

I added the string "Jon" to the end of the array to get an actual grouping, and came up with the following result:

C# LINQPad result

This was exactly what I was expecting. Then, in LINQPad, I went to the VB.NET version of the same query:

' Manually added "Jon"
from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _
group by ng = new with _
{ _
    .FirstLetter = n(0), _
    .Length = n.Length _
} into group

The result does not properly group Jay/Jon together.

VB.NET LINQPad result

After pulling my hair out for a bit, I discovered this MSDN article discussing VB.NET anonymous types. In VB.NET they are mutable by default as opposed to C# where they are immutable. In VB, you need to add the Key keyword to make them immutable. So, I changed the query to this (notice the addition of Key):

from n in new string() { "Tom", "Dick", "Harry", "Mary", "Jay", "Jon" }.AsQueryable() _
group by ng = new with _
{ _
    Key .FirstLetter = n(0), _
    Key .Length = n.Length _
} into group

This gave me the correct result:

enter image description here

So my question is this:

  1. Why does mutability/immutability of anonymous types matter when linq does an equality comparison? Notably, in Linq-to-SQL it doesn't matter at all, which is likely just a product of the translation to SQL. But in Linq-to-objects it apparently makes all the difference.
  2. Why would MS have chosen to make VB's anonymous types mutable. I see no real advantage, and after mucking around with this issue I see some very real disadvantages. Namely that your linq queries can have subtle bugs.

-- EDIT --

Just an interesting extra piece of info... Apparently this is keyed property issue is widely known. I just didn't know what to Google for. It's been discussed here and here on stackoverflow. Here's another example of the issue using anonymous types and Distinct:

Dim items = New String() {"a", "b", "b", "c", "c", "c"}
Dim result = items.Select(Function(x) New With {.MyValue = x}).Distinct()
Dim result2 = items.Select(Function(x) New With {Key .MyValue = x}).Distinct()
'Debug.Assert(result.Count() = 3) ' Nope... it's 6!
Debug.Assert(result2.Count() = 3)

The Key modifier doesn't just affect mutability - it also affects the behaviour of Equals and GetHashCode. Only Key properties are included in those calculations... which clearly affects grouping etc.

As for why it's different for VB - I don't know. It seems odd to me too. I know I'm glad that C# works the way it does though :) Even if it could be argued that making properties optionally mutable makes sense, I don't see why it should be the default.

Count child record and show zero if empty

4 votes

I'm fine with both C# and VB.NET

I have two tables. Authors and Books. It's a one to many relationship, Authors to Books. I'm writing a query to show how many books that each author has.

I wrote the following query:

Dim query = From oa In db.Authors _
         Group oa By oa.Book Into grouping = Group _
         Select Author = Book, Count = grouping.Count(Function(s) s.AuthorId)

This query will give the following result:

             - Author A : 2 books
             - Author B : 3 books
             - Author C: 1 book

But in the Authors table, there are some authors without any books yet. For example, there two authors, Author D and Author E that have no books yet.

I want to write query that includes all authors and number of ther books, even though they don't have any book yet, no record in the Books table yet.

I want to get something like like this:

             - Author A : 2 books
             - Author B : 3 books
             - Author C: 1 book
             - Author D: 0 book
             - Author E: 0 book

Thank you.

Is there a reason for the grouping? Doesn't this work?

db.Authors.Select(a => new { Author, BookCount = a.Books.Count });

Distinct in LINQ with anonymous types (in VB.NET)

2 votes

Supposing the referenced List below contains 2 elements:

Dim Countries = From c In List _
                Select New With { .Country = c.Country, .CountryID = c.CountryID }

the code above returns

.Country=Spain .CountryID = 1
.Country=Spain .CountryID = 1

How can i get the distinct values? The Countries query should contain only

.Country=Spain .CountryID = 1

I can only assume you're dead set on the use of anonymous type as the answer given by Alex Peck is correct. (and I've upvoted it).

However, this boils down to a VB.NET vs C# compiler discussion.

In VB.NET, when an anonymous type is encountered only those properties declared as key properties can be used for comparison purposes. So in VB.NET without key, when you're attempting to do a distinct comparison, nothing will occur.

Read all about it here.

So first, to answer your question, this works with anonymous types:

Dim Countries = From c In List Select New With {Key c.CountryId, c.Country} Distinct.ToList

enter image description here

This is why freedompeace's answer doesn't quite work.

C# however the compiler is a little different.

When an anonymous type is encountered and a comparison operation is needed the c# compiler goes all gang busters and overrides Equals and GetHashCode. It will iterate over all of the public properties of the anonymous type to compute the object's hash code to test for equality.

And you can read more about that here.

Hope this answers your question.

Is there a better solution to this C# List<DateTime> sorting?

0 votes

I am writing a class for an ASP.NET MVC menu. I want to be able to take a list of all blog entries and make an Archive menu similar to this:

1/2011 (2)
3/2011 (1)
4/2011 (12)
etc...

Here is the code that I am using:

public class ArchiveMenuModel
{
    private List<ArchiveMenuItem> menuItems;
    public List<ArchiveMenuItem> MenuItems { get { return menuItems; } }

    public ArchiveMenuModel(List<DateTime> dates, string streamUrl)
    {
        menuItems = new List<ArchiveMenuItem>();
        int itemCount = 0;
        dates = dates.OrderByDescending(x => x).ToList();

        for (int i=0; i<dates.Count; i++)
        {
            itemCount++;
            if(i+1 < dates.Count)
            {
                if(!(dates[i].Month == dates[i + 1].Month && dates[i].Year == dates[i + 1].Year))
                {
                    menuItems.Add(new ArchiveMenuItem(streamUrl, dates[i].Month, dates[i].Year, itemCount));
                    itemCount = 0;
                }
            }
            else
            {
                menuItems.Add(new ArchiveMenuItem(streamUrl, dates[i].Month, dates[i].Year, itemCount));
            }
        }

    }
}

Is there a better way, perhaps by using Linq or something? Specifically, the part of my code that i don't like is:

if(!(dates[i].Month == dates[i + 1].Month && dates[i].Year == dates[i + 1].Year))

If I can avoid such an ugly if statement, that would be great!

Thanks for any input.

menuItems = dates
     .GroupBy(x => new DateTime(x.Year, x.Month, 1))
     .Select(x=> new{Date = x.Key, Count = x.Count()})
     .OrderByDescending(x => x.Date)
     .Select(x => new ArchiveMenuItem(streamUrl, 
                                      x.Date.Month, 
                                      x.Date.Year, 
                                      x.Count))
     .ToList();