分割List< int>分成连续的数字组 [英] Split a List<int> into groups of consecutive numbers
问题描述
我有一个排序的List<int>
,例如{ 1, 2, 3, 4, 6, 7, 9 }
我想将其分为几组-每个组都有这样的连续数字:{ {1, 2, 3, 4}, {6, 7}, {9} }
I have a sorted List<int>
like { 1, 2, 3, 4, 6, 7, 9 }
I want to split that into some groups -- every group has consecutive number like this: { {1, 2, 3, 4}, {6, 7}, {9} }
我知道我可以使用for
循环遍历列表,并在当前值和上一个值之间进行比较,然后决定是追加到最后一个组还是创建一个新组.但我想找到一种漂亮"的方法.也许使用LINQ?
I know I can use for
loop to traverse the list, and compare between the current value and previous value, then decide whether append to last group or create a new group. But I want to find a "pretty" way to do it. Maybe use LINQ?
我从项目 more-itertools找到了python代码:
def consecutive_groups(iterable, ordering=lambda x: x):
for k, g in groupby(
enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
):
yield map(itemgetter(1), g)
推荐答案
以下是我对使用迭代器的扩展方法的建议:
Here is my suggestion for an extension method using iterators:
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> src) {
var more = false; // compiler can't figure out more is assigned before use
IEnumerable<int> ConsecutiveSequence(IEnumerator<int> csi) {
int prevCurrent;
do
yield return (prevCurrent = csi.Current);
while ((more = csi.MoveNext()) && csi.Current-prevCurrent == 1);
}
var si = src.GetEnumerator();
if (si.MoveNext()) {
do
// have to process to compute outside level
yield return ConsecutiveSequence(si).ToList();
while (more);
}
}
我必须说Python算法令人印象深刻,这是它的C#实现:
I must say the Python algorithm is very impressive, here is a C# implementation of it:
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> iterable, Func<int,int> ordering = null) {
ordering = ordering ?? (n => n);
foreach (var tg in iterable
.Select((e, i) => (e, i))
.GroupBy(t => t.i - ordering(t.e)))
yield return tg.Select(t => t.e);
}
这是Python算法的C#单行实现:
Here is a C# one-line implementation of the Python algorithm:
public static IEnumerable<IEnumerable<int>> GroupConsecutive(this IEnumerable<int> iterable, Func<int,int> ordering = null) =>
iterable
.Select((e, i) => (e, i))
.GroupBy(
t => t.i - (ordering ?? (n => n))(t.e),
(k,tg) => tg.Select(t => t.e));
注意:启用了可空注释上下文的C#8应该在两个Python方法中都使用Func<int,int>?
.您还可以使用??=
分配ordering
.
NOTE: C# 8 with nullable annotation context enabled should use Func<int,int>?
in both Python methods. You could also use ??=
to assign ordering
.
这篇关于分割List< int>分成连续的数字组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!