Split a Collection into 'N' Parts With Linq

Split a collection into `n` parts with LINQ?

A pure linq and the simplest solution is as shown below.

static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
int i = 0;
var splits = from item in list
group item by i++ % parts into part
select part.AsEnumerable();
return splits;
}
}

Splitting a list or collection into chunks

Here's an extension method that will work with any list and any size chunks.

public static List<List<T>> SplitList<T>(this List<T> me, int size = 50)
{
var list = new List<List<T>>();
for (int i = 0; i < me.Count; i += size)
list.Add(me.GetRange(i, Math.Min(size, me.Count - i)));
return list;
}

Use it like this:

List<List<string>> chunksOf50 = stuffFromFile.SplitList();

Split List into Sublists with LINQ

Try the following code.

public static List<List<T>> Split<T>(IList<T> source)
{
return source
.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / 3)
.Select(x => x.Select(v => v.Value).ToList())
.ToList();
}

The idea is to first group the elements by indexes. Dividing by three has the effect of grouping them into groups of 3. Then convert each group to a list and the IEnumerable of List to a List of Lists

C# - Splitting a list into n amount of sub-lists

You're trying to partition your list into n parts with equal number of elements?

Try GroupBy:

var splitStudentList = studentList.Select((s, i) => new { s, i })
.GroupBy(x => x.i % numFormTeachers)
.Select(g => g.Select(x => x.s).ToList())
.ToList();

Or you can create your own extension method to do that. I've described how to do it right on my blog: Partitioning the collection using LINQ: different approaches, different performance, the same result.

public IEnumerable<IEnumerable<T>> Partition<T>(IEnumerable<T> source, int size)
{
var partition = new List<T>(size);
var counter = 0;

using (var enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
partition.Add(enumerator.Current);
counter++;
if (counter % size == 0)
{
yield return partition.ToList();
partition.Clear();
counter = 0;
}
}

if (counter != 0)
yield return partition;
}
}

usage:

var splitStudentList = studentList.Partition(numFormTeachers)
.Select(x => x.ToList())
.ToList();

Split a collection into n parts with LINQ, in VB.Net

You can use Range, Skip and Take to achieve your goal.

Dim collection As IEnumerable(Of Integer) = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim parts As Integer = 4
Dim count As Integer = CInt(Math.Ceiling(collection.Count() / parts)) '= 3
Dim result As IEnumerable(Of IEnumerable(Of Integer)) = Nothing

'Method 1:
result = From i In Enumerable.Range(0, count) Select collection.Skip(i * parts).Take(parts)

'Method 2:
result = Enumerable.Range(0, count).Select(Function(i) collection.Skip(i * parts).Take(parts))

For Each item In result
Debug.WriteLine(String.Join(", ", item))
Next

1, 2, 3, 4

5, 6, 7, 8

9, 10

Mandatory extension method:

Public Module Extensions

<System.Runtime.CompilerServices.Extension()>
Public Function Split(Of TSource)(collection As IEnumerable(Of TSource), ByVal parts As Integer) As IEnumerable(Of IEnumerable(Of TSource))
If (collection Is Nothing) Then Throw New ArgumentNullException("collection")
If (parts < 1) Then Throw New ArgumentOutOfRangeException("parts")
Dim count As Integer = collection.Count()
If (count = 0) Then Return {}
If (parts >= count) Then Return {collection}
Return Enumerable.Range(0, CInt(Math.Ceiling(count / parts))).Select(Function(i) collection.Skip(i * parts).Take(parts))
End Function

End Module

result = collection.Split(4)

C# How to split a List in two using LINQ

You can do this in one statement by converting it into a Lookup table:

var splitTables = events.Tolookup(event => event.Closer_User_ID == null);

This will return a sequence of two elements, where every element is an IGrouping<bool, EventModel>. The Key says whether the sequence is the sequence with null Closer_User_Id, or not.

However this looks rather mystical. My advice would be to extend LINQ with a new function.

This function takes a sequence of any kind, and a predicate that divides the sequence into two groups: the group that matches the predicate and the group that doesn't match the predicate.

This way you can use the function to divide all kinds of IEnumerable sequences into two sequences.

See Extension methods demystified

public static IEnumerable<IGrouping<bool, TSource>> Split<TSource>(
this IEnumerable<TSource> source,
Func<TSource,bool> predicate)
{
return source.ToLookup(predicate);
}

Usage:

IEnumerable<Person> persons = ...
// divide the persons into adults and non-adults:
var result = persons.Split(person => person.IsAdult);

Result has two elements: the one with Key true has all Adults.

Although usage has now become easier to read, you still have the problem that the complete sequence is processed, while in fact you might only want to use a few of the resulting items

Let's return an IEnumerable<KeyValuePair<bool, TSource>>, where the Boolean value indicates whether the item matches or doesn't match:

public static IEnumerable<KeyValuePair<bool, TSource>> Audit<TSource>(
this IEnumerable<TSource> source,
Func<TSource,bool> predicate)
{
foreach (var sourceItem in source)
{
yield return new KeyValuePair<bool, TSource>(predicate(sourceItem, sourceItem));
}
}

Now you get a sequence, where every element says whether it matches or not. If you only need a few of them, the rest of the sequence is not processed:

IEnumerable<EventModel> eventModels = ...
EventModel firstOpenEvent = eventModels.Audit(event => event.Closer_User_ID == null)
.Where(splitEvent => splitEvent.Key)
.FirstOrDefault();

The where says that you only want those Audited items that passed auditing (key is true).

Because you only need the first element, the rest of the sequence is not audited anymore

Split a entity collection into n parts

Try something like this:

var result = dbContext.VisitDates
.GroupBy(x => x.VisitMeDate.Date)
.Where(g => g.Count() == 3)
.Select(g => g.ToList())
.ToList();

Split list into N sublist with balanced size C#

Your are rounding off, instead of up:

var playersXGroup = (int)Math.Round(players.Count / numberGroupsRound);

should be

var playersXGroup = (int)Math.Ceiling(players.Count / numberGroupsRound);

Split a collection into parts based on condition with LINQ?

Here's one possible LINQ answer, though I'm sure a more efficient one exists:

    inv
.GroupBy(x => new { CustomerName = x.CustomerName, Date = x.Date })
.SelectMany(x => x
.OrderBy(y => y.SortOrder)
.Select((y,i) => new { Value = y, Sort = y.SortOrder - i })
.GroupBy(y => y.Sort)
.Select(y => y.Select(z => z.Value))
)


Related Topics



Leave a reply



Submit