kosnkov
kosnkov

Reputation: 5941

Order by item from list inside list

i have list of items of following class:

public class MonthlyConsumption : UserData
{
    public string Unit { get; set; }

    public List<DailyConsumption> DailyConsumptions { get; set; }
}

public class DailyConsumption
{
    public DateTime Day { get; set; }
    public double? Value { get; set; }
}

so as you can see, i have list of items where each item has also list of days inside.

My question is how can I order my main list by specyfic element inside inner list.

Example: I have list of type MonthlyConsumption. Each element of that list has collection of type DailyConsumption, and this collection is has day 10 days from January this year. How can I order my main list by 1 of Jan?

Update: I am afraid i put my problem in wrong words, what i really want to do is to order my list of type MonthlyConsumption where each item has his own list of type DailyConsumption by Value at specific Day so if each item in my list has 10 days in his inner collection from jan 1 till 10, i want to ordery my main list by value in jan 1.

Update I tried

return monthlyConsumption.OrderBy(x => x.DailyConsumptions.Where(y => y.Day.Day == 1))
                         .ToList();

but it gives me At least one object must implement IComparable.

Upvotes: 2

Views: 4192

Answers (3)

Pablo Romeo
Pablo Romeo

Reputation: 11406

If I understood correctly, maybe something like this is what you are after:

var targetDay = DateTime.Now; //set to Jan 1st
var result =
    monthylConsumptions.OrderBy(
        x =>
        x.DailyConsumptions.Where(y => y.Day.Date == targetDay.Date).Select(z => (!z.Value.HasValue ? 0 : z.Value.Value)).SingleOrDefault());

"targetDay" should be set to Jan 1st, per your example.

This will sort ascending, by Value on the day you specify, and consider the default value whenever there isn't one in that specific monthly.

EDIT: I just tested the following unit test, and it passes, without showing the error you are describing:

[TestFixture]
public class LinqSortTest
{
    public class MonthlyConsumption
    {
        public string Unit { get; set; }

        public List<DailyConsumption> DailyConsumptions { get; set; }
    }

    public class DailyConsumption
    {
        public DateTime Day { get; set; }
        public double? Value { get; set; }
    }

    [Test]
    public void SomeTest()
    {
        var targetDay = new DateTime(2013, 1, 1);
        var monthlyConsumptions = new List<MonthlyConsumption>();
        monthlyConsumptions.Add(new MonthlyConsumption
            {
                Unit = "first",
                DailyConsumptions = new List<DailyConsumption>
                    {
                                new DailyConsumption { Day = new DateTime(2013, 1, 1), Value = 5 },
                                new DailyConsumption { Day = new DateTime(2013, 1, 5), Value = 100 }
                    }
            });
        monthlyConsumptions.Add(
            new MonthlyConsumption
                {
                    Unit = "second",
                    DailyConsumptions =
                        new List<DailyConsumption>
                            {
                                new DailyConsumption { Day = new DateTime(2013, 1, 1), Value = 2 },
                                new DailyConsumption { Day = new DateTime(2013, 1, 5), Value = 1 }
                            }
                });

        var result =
            monthlyConsumptions.OrderBy(
                x =>
                x.DailyConsumptions.Where(y => y.Day.Date == targetDay.Date).Select(
                    z => (!z.Value.HasValue ? 0 : z.Value.Value)).SingleOrDefault()).ToList();

        Assert.AreEqual("second", result[0].Unit);
    }
}

As you can see, the Assert confirms that indeed the second item was placed first, because the Jan 1st value for "second" was lower than on "first".

Upvotes: 1

Episodex
Episodex

Reputation: 4559

Try:

monthlyConsumptions
    .SelectMany(mc => mc.DailyConsumptions)
    .Where(dc = > dc.Day.Date.Day == 1 && dc.Day.Date.Month == 1)
    .OrderBy(dc => dc.Value)
    .Select(dc => dc.MonthlyConsumption);

This will get all DailyConsumptions for all MonthlyConsumptions, then filter only those from 1st of Jan, order them by Value and instead of getting any data from it, it returns parent entity which is MonthlyConsumption.

So you get IQuerable<MonthlyConsumption> ordered as you wished.

EDIT: That will work in LINQ to Entities, in your case probably not unfortunately, unless you have parent property in DailyConsumption called MonthlyConsumption.

Upvotes: 1

Jeremy Wiggins
Jeremy Wiggins

Reputation: 7299

I haven't tested it, but I believe you can do it with Linq.

Assume that "monthlyConsumptions" is a List<MonthlyConsumption>.

monthlyConsumptions.OrderBy(mc => mc.DailyConsumptions.Min(dc => dc.Day));

This will order your list of MonthlyConsumptions by their earliest DailyConsumption.

Upvotes: 4

Related Questions