Arnab
Arnab

Reputation: 2354

Splitting a list of objects based on a property c#

myClass structure :

public class myClass
    {
        public string Name { get; set; }
        public string AdditionalData { get; set; }
        public System.DateTime ActivityTime { get; set; }
    }

I have a list of the above class List<myClass> all ordered by ActivityTime.

I need to split the above list and get a List<List<myClass>> such that if there is a difference of more than a specific period say 5 mins between two consecutive ActivityTime I wish the split to take place.

Any help is sincerely appreciated.

Thanks

Upvotes: 0

Views: 1214

Answers (3)

Hari Prasad
Hari Prasad

Reputation: 16956

Various approaches this can be achieved, but underlying principle is same. Keep track of n-1(th) element when processing n(th) element and calculate timespan between these two.

You could do something like this.

List<MyClass> data = ...; // input
int gid=0;
DateTime prevvalue = data[0].ActivityTime;                          // Initial value 

var result =  data.Select(x=>
{
    var obj =  x.ActivityTime.Subtract(prevvalue).TotalMinutes<5?  // Look for timespan difference
                 new {gid= gid, item =x}                          // Create groups based on consecutive gaps. 
                :new {gid= ++gid, item =x};
    prevvalue= x.ActivityTime;                                      // Keep track of previous value (for next element process)
    return obj;
})
.GroupBy(x=>x.gid)                                                  // Split into groups 
.Select(x=>x.Select(s=>s.item).ToList())
.ToList();

Check this Demo

Upvotes: 2

Slava Utesinov
Slava Utesinov

Reputation: 13488

What about this solution:

var data = new List<myClass> {
    new myClass { ActivityTime = new DateTime(2016, 01, 01, 01, 00, 00) },
    new myClass { ActivityTime = new DateTime(2016, 01, 01, 01, 05, 00) },
    new myClass { ActivityTime = new DateTime(2016, 01, 01, 01, 06, 00) },
    new myClass { ActivityTime = new DateTime(2016, 01, 01, 01, 07, 00) },
    new myClass { ActivityTime = new DateTime(2016, 01, 01, 01, 17, 00) }
};

var period = 5;
var firstActivityTime = data.Min(x => x.ActivityTime);
var answer = data.OrderBy(x => x.ActivityTime).GroupBy(x => {
        var dif = (x.ActivityTime - firstActivityTime).Minutes;
        return dif / period - (dif % period == 0 && dif / period != 0 ? 1 : 0);
    }).Select(x => x.ToList()).ToList();

Upvotes: 3

Zein Makki
Zein Makki

Reputation: 30032

You can do that in a simple iteration:

var myList = new List<myClass>()
{
    new myClass() { Name = "ABC", AdditionalData = "1", ActivityTime = DateTime.Now },
    new myClass() { Name = "ABC2", AdditionalData = "2", ActivityTime = DateTime.Now },
    new myClass() { Name = "ABC3", AdditionalData = "3", ActivityTime = DateTime.Now.AddSeconds(6) },
    new myClass() { Name = "ABC4", AdditionalData = "3", ActivityTime = DateTime.Now.AddSeconds(11) },
    new myClass() { Name = "ABC4", AdditionalData = "3", ActivityTime = DateTime.Now.AddSeconds(12) }
};

var results = new List<List<myClass>>();

myClass previousItem = null;
List<myClass> currentList = new List<myClass>();
foreach (var item in myList)
{
    if (previousItem == null || (item.ActivityTime - previousItem.ActivityTime).TotalSeconds >= 5)
    {
        currentList = new List<myClass>();
        results.Add(currentList);
    }

    currentList.Add(item);
    previousItem = item;
}

Upvotes: 3

Related Questions