C# - elegant way of partitioning a list?
Here is an extension method that will do what you want:
public static IEnumerable<List<T>> Partition<T>(this IList<T> source, Int32 size)
{
for (int i = 0; i < (source.Count / size) + (source.Count % size > 0 ? 1 : 0); i++)
yield return new List<T>(source.Skip(size * i).Take(size));
}
Edit: Here is a much cleaner version of the function:
public static IEnumerable<List<T>> Partition<T>(this IList<T> source, Int32 size)
{
for (int i = 0; i < Math.Ceiling(source.Count / (Double)size); i++)
yield return new List<T>(source.Skip(size * i).Take(size));
}
What is the best way to partition a collection into smaller collections
I use this extension method for my code
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> t, int size)
{
while (t.Any())
{
yield return t.Take(size);
t = t.Skip(size);
}
}
What is the simplest way to partition a list based on a criteria?
Two LINQ statements would do:
var nameNotNull = objectList.Where(o => !string.IsNullOrEmpty(o.Name));
var nameNull = objectList.Where(o => string.IsNullOrEmpty(o.Name));
Of course, you could use GroupBy
, or a more efficient foreach
statement.
To show the foreach
option:
List<MyObject> nameNotNull = new List<MyObject>();
List<MyObject> nameNull = new List<MyObject>();
foreach (MyObject o in objectList)
{
if (!string.IsNullOrEmpty(o.Name))
{
nameNotNull.Add(o);
}
else
{
nameNull.Add(o);
}
}
Partition list by delimiter
Directly in Linq, I think it will be hard, but you can create a custom operator. Maybe something like this :
List<String> test = new List<String>() { "1", "8", ";", "2", "7", "42", ";", "3" };
var restul = test.StrangePartition(";");
with :
public static class Helper
{
public static IEnumerable<IEnumerable<T>> StrangePartition<T>(this IEnumerable<T> source, T partitionKey)
{
List<List<T>> partitions = new List<List<T>>();
List<T> partition = new List<T>();
foreach (T item in source)
{
if (item.Equals(partitionKey))
{
partitions.Add(partition);
partition = new List<T>();
}
else
{
partition.Add(item);
}
}
partitions.Add(partition);
return partitions;
}
}
Efficiently partition list into chunks of a fixed size
Since I'm using the partitions locally, I ended up chosing to invert the situation: instead of passing the partitions to the action using it, I can pass the action to the function doing the partitioning.
Public Sub DoForPartition(Of T)(source As IEnumerable(Of T),
size As Integer,
doThis As Action(Of IEnumerable(Of T)))
Dim partition(size - 1) As T
Dim count = 0
For Each t in source
partition(count) = t
count += 1
If count = size Then
doThis(partition)
count = 0
End If
Next
If count > 0 Then
Array.Resize(partition, count)
doThis(partition)
End If
End Sub
This function avoids looping through the source multiple times and the only memory overhead is the size of the partition (instead of the entire source like some of the other options). I didn't write this function myself, but adapted a similarly looking C# function from this answer.
This looks like a much better algorithm than the one in my question.
LINQ Partition List into Lists of 8 members
Use the following extension method to break the input into subsets
public static class IEnumerableExtensions
{
public static IEnumerable<List<T>> InSetsOf<T>(this IEnumerable<T> source, int max)
{
List<T> toReturn = new List<T>(max);
foreach(var item in source)
{
toReturn.Add(item);
if (toReturn.Count == max)
{
yield return toReturn;
toReturn = new List<T>(max);
}
}
if (toReturn.Any())
{
yield return toReturn;
}
}
}
How to divide an array into two?
Assuming you just need to split an array (or List
) of elements into first/second half - usually one would use Enumerable.Take
/Enumerable.Skip
followed by Enumerable.ToArray
to convert to array if necessary:
string[] Player1Array = GetImages().Take(20).ToArray();
string[] Player2Array = GetImages().Skip(20).ToArray();
When to use Partitioner class?
The Partitioner
class is used to make parallel executions more chunky. If you have a lot of very small tasks to run in parallel the overhead of invoking delegates for each may be prohibitive. By using Partitioner
, you can rearrange the workload into chunks and have each parallel invocation work on a slightly larger set. The class abstracts this feature and is able to partition based on the actual conditions of the dataset and available cores.
Example: Imagine you want to run a simple calculation like this in parallel.
Parallel.ForEach(Input, (value, loopState, index) => { Result[index] = value*Math.PI; });
That would invoke the delegate for each entry in Input. Doing so would add a bit of overhead to each. By using Partitioner
we can do something like this
Parallel.ForEach(Partitioner.Create(0, Input.Length), range => {
for (var index = range.Item1; index < range.Item2; index++) {
Result[index] = Input[index]*Math.PI;
}
});
This will reduce the number of invokes as each invoke will work on a larger set. In my experience this can boost performance significantly when parallelizing very simple operations.
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 List
s
How to do partitioning in combination with Service Fabric Remoting
Here's a video that covers this subject and here's a working code sample that goes with it.
- use a (proper e.g. FNV) hash algorithm to get the hash of
username
, use thelong
result to determine anInt64RangePartition
by its key. - use a gateway that does the hashing for you (e.g. api management, or a custom stateless service) and forwards the call
- you could use customer headers to pass the
username
. (the sample doesn't)
Related Topics
Linq: How to Exclude Condition If Parameter Is Null
Directory.Getcurrentdirectory() Not Working on Linux
Use or Clause in Queryover in Nhibernate
Enter Key Pressed Event Handler
How to Protect This Function from SQL Injection
Multiple Producers, Single Consumer
Solving a Timeout Error for SQL Query
What Is the Equivalent of "Case When Then" (T-Sql) with Entity Framework
Update Float Array from C++ Native Plugin
Why Is ASP.NET Identity Identitydbcontext a Black-Box
String List in SQLcommand Through Parameters in C#
Is the Destructor Called If the Constructor Throws an Exception