David DeMar
David DeMar

Reputation: 2650

How to group a list of lists by date using Linq?

Here is a simplified version of my class structure:

public class TransferObject
{
    public List<Event> events { get; set; }

    public TransferObject()
    {
        events = new List<Event>();
    }
}

public class Event
{
    public List<Data> eventData { get; set; }

    public Event()
    {
        eventData = new List<Data>();
    }
}

public class Data
{
    public int someData {get; set;}
    public DateTime date { get; set; }
}

What I want to do is take all the Data objects in the eventData lists and put them in a new grouped list of lists that's grouped by date.

I thought about putting all the Data objects into a temporary list and then grouping that list with Linq but I'd like to know if there's a more elegant way to do it without using a temporary list.

Upvotes: 3

Views: 16162

Answers (2)

moron4hire
moron4hire

Reputation: 713

Well, it depends on the data you're looking for. If you don't care about the actual Date values, just that the integers are grouped by them (and I suspect also sorted by them), from a reference to the Event class you would have:

List<List<int>> byDate = evt.eventData
    .GroupBy(d => d.date)
    .OrderBy(g=>g.Key)
    .Select(g => g.Select(v => v.someData)
        .ToList())
    .ToList();

However, if you care about the dates, there are two ways you could possibly go. You can end up discarding any references to the Data class:

Dictionary<DateTime, List<int>> byDate2 = evt.eventData
    .GroupBy(d => d.date)
    .OrderBy(g=>g.Key)
    .ToDictionary(
        g=>g.Key, 
        g => g.Select(v => v.someData)
            .ToList());

Or you can keep the Data objects:

List<List<Data>> byDate = evt.eventData
    .GroupBy(d => d.date)
    .OrderBy(g => g.Key)
    .Select(g => g.ToList())
    .ToList();

But supposing you wanted to do this from a reference to the TransferObject class. Then, you would do pretty much the same thing, but would need to use the SelectMany function:

TransferObject txobj = new TransferObject(); // however this happens
List<List<int>> byDate = txobj.events
    .SelectMany(evt=>evt.eventData
        .GroupBy(d => d.date)
        .OrderBy(g => g.Key)
        .Select(g => g.Select(v => v.someData)
            .ToList()))
    .ToList();

Dictionary<DateTime, List<int>> byDate2 = txobj.events
    .SelectMany(e=>e.eventData)
    .GroupBy(d => d.date)
    .OrderBy(g=>g.Key)
    .ToDictionary(
        g=>g.Key, 
        g => g.Select(v => v.someData)
            .ToList());

List<List<Data>> byDate3 = txobj.events
    .SelectMany(evt=>evt.eventData
        .GroupBy(d => d.date)
        .OrderBy(g => g.Key)
        .Select(g => g.ToList()))
    .ToList();

The key here is that the SelectMany function essentially concatenates one level of collections that a normal Select would return, i.e.

any IEnumerable<IEnumerable<T>> becomes an IEnumerable<T>.

Upvotes: 6

p.s.w.g
p.s.w.g

Reputation: 148990

If I understand what you want, something like this should work:

var results = 
    from e in transferObject.events
    from d in e.eventData
    group d by d.date;

Or in fluent syntax:

var results = transferObject.events
    .SelectMany(e => e.eventData)
    .GroupBy(d => d.date);

Upvotes: 11

Related Questions