LINQ: Divide the list into groups by weight / size

I have many examples of using LINQ, how to split a list into a list according to the maximum elements in each list. But in this case, I am interested in diving sub-lists using sizemb as the weight - with a maximum file size in the 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 be divided into 3 lists. If any "files" are more than 9 mb, 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); } 
+6
source share
2 answers

You can 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 is a demo: http://ideone.com/OkXw7C

 dok1 dok2 dok3,dok4 
+7
source

You can use the Aggregate function for this, the by group will work only when comparing values ​​that are not based on an arbitrary condition, 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; } ) 
0
source

Source: https://habr.com/ru/post/945233/


All Articles