Search code examples
c#linqsublisttobjectlist

How to Split a object list into sublists grouping by elements(dateTime and String) C#


Im tring to make sub-list based on main list with 9 records according to datetime ascending order & then pcName(string).

my sorted sublist need to be like below

ObjectList 1 :

2615,2019-11-22 16:03:22.150,Test1

2615,2019-11-22 16:03:22.200,Test1

2615,2019-11-22 16:03:22.250,Test1

2615,2019-11-22 16:03:22.300,Test1

ObjectList 2 :

2615,2019-11-22 16:03:22.350,Test2

2615,2019-11-22 16:03:22.400,Test2

ObjectList 3 :

2615,2019-11-22 16:03:22.450,Test1

2615,2019-11-22 16:03:22.500,Test1

ObjectList 4 :

2615,2019-11-22 16:03:22.550,Test3

This object list need to take according to sequence ObjectList[0] ,ObjectList[1] ,ObjectList[2] and ObjectList[3]

I mentioned below my sample code

But this only provides me 3 sublist sets(Item1) filter based with Test1, Test2 & Test3 and 9 sublists but i want as above 4 sub lists. where i want to change code ?? Please help me

private void button_Click(object sender, EventArgs e)
        {
            List<Identity> listOfIdentity = new List<Identity>()
            {
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"),PcName="Test3"},                              
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},                            
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
               new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}              
            };
            List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name

            var items1 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => x.PcName).Select(grp => grp.ToList()).ToList(); //sub list create based with **Test1, Test2 & Test3** (3 sub lists)
            var items2 = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).GroupBy(x => new { x.QCTime, x.PcName }).Select(grp => grp.ToList()).ToList(); //sub list create based with each time and pc name (9 sublists)
        }

        class Identity
        {
            public int id { get; set; }
            public DateTime QCTime { get; set; }
            public string PcName { get; set; }
        }

Solution

  • Here is my solution using Linq.Aggregate:

    private void button_Click(object sender, EventArgs e)
    {
        List<Identity> listOfIdentity = new List<Identity>()
        {
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.550"), PcName="Test3"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.300"), PcName="Test1"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.350"), PcName="Test2"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.400"), PcName="Test2"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.200"), PcName="Test1"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.500"), PcName="Test1"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.250"), PcName="Test1"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.450"), PcName="Test1"},
            new Identity() {id= 2615,QCTime=DateTime.Parse("2019-11-22 16:03:22.150"), PcName="Test1"}
        };
        List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList(); // here i order by time and then pc name
        var result = sortedIdentity.Skip(1).Aggregate(new List<List<Identity>> { new List<Identity> { sortedIdentity[0] } }, (lists, curr) =>
        {
            if (curr.PcName == lists.Last()[0].PcName)
                lists.Last().Add(curr);
            else
                lists.Add(new List<Identity> { curr });
            return lists;
        });
    }
    

    It iterates over each element and checks, if it's PcName is the same as previous. If it is, it goes on the same list, else new list is created with this element.


    EDIT: More elegant solution suggested by Matt.G

        List<Identity> sortedIdentity = listOfIdentity.OrderBy(x => x.QCTime).ThenBy(x => x.PcName).ToList();
        var result = sortedIdentity.Aggregate(new List<List<Identity>>(), (lists, curr) => 
       { 
            if (curr.PcName == lists.LastOrDefault()?.FirstOrDefault()?.PcName)
                lists.Last().Add(curr);
            else
                lists.Add(new List<Identity> { curr });
            return lists;
        });