您好,是否已经实现了任何有效的方法来获取 Haskell Data.List.span
的功能?
span :: (a -> Bool) -> [a] -> ([a], [a])
基本上给定一个列表
和一个谓词
,我想在第一次出现错误谓词后将列表分成两部分。元素在测试 False
的 pivot
元素之后可能会也可能不会遵守谓词,但我不在乎。
List: [1,2,3,1,2,3]
Predicate: x<3
Span: `span (x<3) [1,2,3,1,2,3]` => `([1,2],[3,1,2,3])`
更新
我不关心第一个 false 谓词之后的元素。我只想在第一次出现 False 谓词时拆分列表。第一个 False
谓词之后的序列可以是 True
,但我仍然想将其拆分。
最佳答案
如果您对使用列表感到满意,那么您可以通过源列表进行一次传递来创建两个新列表,如下所示:
public static (List<T> part1, List<T> part2) SplitListBy<T>(List<T> source, Predicate<T> splitWhen)
{
var part1 = new List<T>();
int i;
for (i = 0; i < source.Count && !splitWhen(source[i]); ++i)
part1.Add(source[i]);
var part2 = source.GetRange(i, source.Count - i);
return (part1, part2);
}
这应该非常高效。请注意,这使用元组返回两个列表,这需要 C# 7 或更高版本。如果您无法使用 c# 7+,则必须更改代码以使用 out
参数返回列表之一。
测试代码:
var list = new List<int>{ 1, 2, 3, 1, 2, 3 };
var (part1, part2) = SplitListBy(list, item => item >= 3);
Console.WriteLine(string.Join(", ", part1));
Console.WriteLine(string.Join(", ", part2));
输出:
1, 2
3, 1, 2, 3
<小时/>
如果您不需要两个新列表,而只想将原始列表用于一部分,而将一个新列表用于另一部分,则可以这样做:
public static List<T> SplitListBy<T>(List<T> source, Predicate<T> splitWhen)
{
int i;
for (i = 0; i < source.Count && !splitWhen(source[i]); ++i)
;
var part2 = source.GetRange(i, source.Count - i);
source.RemoveRange(i, source.Count - i);
return part2;
}
测试代码非常相似:
var list = new List<int>{ 1, 2, 3, 1, 2, 3 };
var part2 = SplitListBy(list, item => item >= 3);
Console.WriteLine(string.Join(", ", list));
Console.WriteLine(string.Join(", ", part2));
(输出与其他测试代码相同。)
关于c# - 在 C# 中相当于 Haskell 的 Data.List.Span,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60415346/