我想在项目上对collection
进行分区,这与特定条件相匹配。我可以使用TakeWhile
和SkipWhile
来做到这一点,这很容易理解:
public static bool IsNotSeparator(int value) => value != 3;
var collection = new [] { 1, 2, 3, 4, 5 };
var part1 = collection.TakeWhile(IsNotSeparator);
var part2 = collection.SkipWhile(IsNotSeparator);
但这会从collection
开始两次迭代,如果IsNotSeparator
需要很长时间,则可能是性能问题。
更快的方法是使用类似的东西:
var part1 = new List<int>();
var index = 0;
for (var max = collection.Length; index < max; ++index) {
if (IsNotSeparator(collection[i]))
part1.Add(collection[i]);
else
break;
}
var part2 = collection.Skip(index);
但这比第一个例子的可读性更低。
所以我的问题是:在特定元素上对collection
进行分区的最佳解决方案是什么?
我将上述两者结合起来的是:
var collection = new [] { 1, 2, 3, 4, 5 };
var part1 = collection.TakeWhile(IsNotSeparator).ToList();
var part2 = collection.Skip(part1.Count);
答案 0 :(得分:0)
这是一个快速示例,说明如何在不使用LINQ的情况下执行更通用的方法(多个拆分,如注释中所述)(可以将其转换为LINQ,但我不确定它是否会更多可读,我现在稍微匆忙):
public static IEnumerable<IEnumerable<T>> Split<T>(this IList<T> list, Predicate<T> match)
{
if (list.Count == 0)
yield break;
var chunkStart = 0;
for (int i = 1; i < list.Count; i++)
{
if (match(list[i]))
{
yield return new ListSegment<T>(list, chunkStart, i - 1);
chunkStart = i;
}
}
yield return new ListSegment<T>(list, chunkStart, list.Count - 1);
}
代码假定一个名为ListSegment<T> : IEnumerable<T>
的类,它只是在原始列表上从from
迭代到to
(没有复制,类似于ArraySegment<T>
的工作方式(但不幸的是限于数组)。
因此代码将返回与匹配项一样多的块,即此代码:
var collection = new[] { "A", "B", "-", "C", "D", "-", "E" };
foreach (var chunk in collection.Split(i => i == "-"))
Console.WriteLine(string.Join(", ", chunk));
会打印:
A, B
-, C, D
-, E
答案 1 :(得分:0)
如何使用Array Copy方法:
var separator = 3;
var collection = new [] { 1, 2, 3, 4, 5 };
var i = Array.IndexOf(collection,separator);
int[] part1 = new int[i];
int[] part2 = new int[collection.Length - i];
Array.Copy(collection, 0, part1, 0, i );
Array.Copy(collection, i, part2, 0, collection.Length - i );
或者更有效地使用ArraySegment:
var i = Array.IndexOf(collection,separator);
var part1 = new ArraySegment<int>( collection, 0, i );
var part2 = new ArraySegment<int>( collection, i, collection.Length - i );
ArraySegment是一个数组的包装器,用于分隔该数组中的一系列元素。多个ArraySegment实例可以引用相同的原始数组并且可以重叠。
编辑 - 添加原始问题与ArraySegment的组合,以便不再迭代集合两次。
public static bool IsNotSeparator(int value) => value != 3;
var collection = new [] { 1, 2, 3, 4, 5 };
var index = collection.TakeWhile(IsNotSeparator).Count();
var part1 = new ArraySegment<int>( collection, 0, index );
var part2 = new ArraySegment<int>( collection, index, collection.Length - index );