Almost every single programming language has a string split function:
foreach (var partition in "12304508".Split("0"))
{
Console.WriteLine(partition);
}
// Output:
// 123
// 45
// 8
Is there any way to do the same but for a generic list instead of a string, i.e. something like:
int[] nums = new int[] {1, 2, 3, 0, 4, 5, 0, 8}; // can be any generic type instead of int
foreach (var partition in nums.SomeLinqFunctionHere(0))
{
Console.WriteLine(partition);
}
// Expected output:
// int[]{1, 2, 3}
// int[]{4, 5}
// int[]{8}
What's the easiest way of doing that?
CodePudding user response:
Try the following:
public static class EnumerableExtensions
{
public static IEnumerable<T[]> SplitEnumerable<T>(this IEnumerable<T> enumerable, T byValue)
{
return SplitEnumerable(enumerable, byValue, EqualityComparer<T>.Default);
}
public static IEnumerable<T[]> SplitEnumerable<T>(this IEnumerable<T> enumerable, T byValue, IEqualityComparer<T> comparer)
{
List<T> buffer = new List<T>();
foreach (var v in enumerable)
{
if (comparer.Equals(v, byValue))
{
yield return buffer.ToArray();
buffer.Clear();
}
else
{
buffer.Add(v);
}
}
yield return buffer.ToArray();
}
}
CodePudding user response:
This should work and is flexible in a way that you can split by conditions instead of only values:
public static IEnumerable<IList<T>> SplitBy<T>(this IEnumerable<T> sequence, Predicate<T> matchFilter)
{
List<T> list = new List<T>();
foreach(T item in sequence)
{
if (matchFilter(item))
{
yield return list;
list = new List<T>();
}
else
{
list.Add(item);
}
}
if (list.Any()) yield return list;
}
Use:
int[] nums = new int[] { 1, 2, 3, 0, 4, 5, 0, 8 }; // can be any generic type instead of int
foreach (var partition in nums.SplitBy(i => i == 0))
{
Console.WriteLine(String.Join(",", partition));
}