Reputation: 2275
I have list classes as below. I need to slipt List<TimeSheet>
base on List<Activity>
count. If activity is greater than 8 then List split by two sublists along with List 0-7 and 7-onward. remain value should be the same in List like employee name and activity hours.
More Detail: I am adding some more detail. Time has only one entry but internal Activity has 10 entries. I need to split the Time with two lists. the first-time list consumes 0-7 activity and another time list consumes 8-onward. So EmployeeName should be the same in both the child list. only Activity lists are different. In new lists, One list has 8 activity entries and another has 2 activity entries.
List<TimeSheet> Time;
сlass TimeSheet
{
public string employeeName {get;set;}
public List<Activity> activity {get;set;}
public List<ActivityHours> ActivityHours{get;set;}
}
class Activity
{
public string Id {get;set;}
public string Activity {get;set;}
}
class ActivityHours
{
public string ActivityId {get;set;}
public string hours {get;set;}
}
Upvotes: 0
Views: 168
Reputation: 117154
This seems rather simple with Take()
and Skip()
.
List<TimeSheet> result =
Time
.SelectMany(t => new []
{
new TimeSheet()
{
employeeName = t.employeeName,
activity = t.activity.Take(8).ToList(),
ActivityHours = t.ActivityHours,
},
new TimeSheet()
{
employeeName = t.employeeName,
activity = t.activity.Skip(8).ToList(),
ActivityHours = t.ActivityHours,
},
})
.Where(t => t.activity.Any())
.ToList();
Upvotes: 0
Reputation: 411
The follwing is also doing the job, but in a different way than @Bizhan's solution
List<TimeSheet> SplitList =
TimeList.Aggregate(new List<TimeSheet>(),
(accList, timeSheet) =>
{
if ((timeSheet.Activities?.Count ?? 0) > 8)
{
accList.Add(new TimeSheet
{
EmployeeName = timeSheet.EmployeeName,
ActivityHours = timeSheet.ActivityHours.ToList(),
Activities = timeSheet.Activities.GetRange(0, 8)
});
accList.Add(new TimeSheet
{
EmployeeName = timeSheet.EmployeeName,
ActivityHours = timeSheet.ActivityHours,
Activities = timeSheet.Activities.GetRange(8, timeSheet.Activities.Count - 8)
});
}
else
{
accList.Add(timeSheet);
}
return accList;
},
accList => accList);
Upvotes: 1
Reputation: 17115
If you don't care about ActivityHours having the same reference across different chunks of activity you can use this code:
var newTime = Time
.SelectMany(t =>
Enumerable
.Range(0, (t.activity.Count - 1) / 8)
.Select(i => new TimeSheet
{
employeeName = t.employeeName,
ActivityHours = t.ActivityHours,
activity = t.activity.GetRange(i * 8, Math.Min(8, t.activity.Count))
}))
.ToList();
Note that Enumerable.Range(0, count)
returns an Enumerable<int>
like [0, 1,... , count-1]
and (t.activity.Count - 1) / 8
is to not have a TimeSheet at the end with an empty activity in case the count was multiple of 8.
activity.GetRange(i, count)
returns an Enumerable<Activity>
with size of count starting from 'i'th element of activity
and Math.Min(8, t.activity.Count)
is to prevent argument out of range.
if you want to make them independent, you can clone it:
var newTime = Time
.SelectMany(t =>
Enumerable
.Range(0, (t.activity.Count - 1) / 8)
.Select(i => new TimeSheet
{
employeeName = t.employeeName,
ActivityHours =
(t.activity.Count < 8) ?
t.ActivityHours :
t.ActivityHours.Select(h => new ActivityHours
{
ActivityId = h.ActivityId,
hours = h.hours
}).ToList(),
activity = t.activity.GetRange(i * 8, Math.Min(8, t.activity.Count))
}))
.ToList();
Upvotes: 1