Reputation: 1027
I've many examples using LINQ how to divide a list into sub-list according to max items in each list. But In this case I'm interested in diving a sub-lists using sizemb as a weight - having a max total filesize per list of 9mb.
public class doc
{
public string file;
public int sizemb;
}
var list = new List<doc>()
{
new doc { file = "dok1", sizemb = 5 },
new doc { file = "dok2", sizemb = 5 },
new doc { file = "dok3", sizemb = 5 },
new doc { file = "dok4", sizemb = 4 },
};
int maxTotalFileSize = 9;
The above list should then be divided into 3 lists. If any 'files' are more than 9mb they should be in their own list.
I made a non LINQ-version here:
var lists = new List<List<doc>>();
foreach (var item in list)
{
//Try and place the document into a sub-list
var availableSlot = lists.FirstOrDefault(p => (p.Sum(x => x.sizemb) + item.sizemb) < maxGroupSize);
if (availableSlot == null)
lists.Add(new List<doc>() { item });
else
availableSlot.Add(item);
}
Upvotes: 6
Views: 1478
Reputation: 460138
You could use this method:
IEnumerable<IList<doc>> SplitDocumentList(IEnumerable<doc> allDocuments, int maxMB)
{
var lists = new List<IList<doc>>();
var list = new List<doc>();
foreach (doc document in allDocuments)
{
int totalMB = list.Sum(d => d.sizemb) + document.sizemb;
if (totalMB > maxMB)
{
lists.Add(list);
list = new List<doc>();
}
list.Add(document);
}
if (list.Count > 0)
lists.Add(list);
return lists;
}
Here's a demo: http://ideone.com/OkXw7C
dok1
dok2
dok3,dok4
Upvotes: 7
Reputation: 21742
You can use the Aggregate function to do that, the group by will only work when comparing values not based on an arbitrary condition of when to start a new group
list.Aggregate(new List<List<doc>>(), (acc,d) => {
if(acc.last().Sum(x => x.sizemb) + d.sizemb > 9) {
acc.Add(new List<doc>());
}
acc.last().Add(d);
return acc;
}
)
Upvotes: 0