Joh*_*ies 5 c# linq algorithm list
我有一个整数列表.我想在该列表中找到所有连续数字的运行,由起始索引和长度定义.因此,例如,对于输入列表[1,2,3,5,7,8],输出将是[{1,3}, {5,1}, {7,2}].这很容易使用循环,类似这样(未经测试的伪代码):
for(i=1, i < maxNum; i++)
{
number = list[i];
previousNumber = list[i-1];
if(number - previousNumber == 1)
{
runLength++;
}
else
{
result.Add(startingNumber, runLength);
runLength = 1;
startingNumber = number;
}
}
Run Code Online (Sandbox Code Playgroud)
但我认为可以使用LINQ.任何想法如何做到这一点?
一种linqish方式可以编写 GroupWhile如下所示的扩展方法(省略所有检查.未优化以便于理解.)
int[] list = new int[] { 1, 2, 3, 5, 7, 8 };
var result = list.GroupWhile((x, y) => y - x == 1)
.Select(x => new {i = x.First(), len = x.Count() })
.ToList();
Run Code Online (Sandbox Code Playgroud)
public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T,T,bool> condition)
{
T prev = seq.First();
List<T> list = new List<T>() { prev };
foreach(T item in seq.Skip(1))
{
if(condition(prev,item)==false)
{
yield return list;
list = new List<T>();
}
list.Add(item);
prev = item;
}
yield return list;
}
Run Code Online (Sandbox Code Playgroud)
TODO:用IGrouping:)
这似乎是一个合理的方法:
Range,因此每个元素都与其索引元组var list = new int[] { 1, 2, 3, 5, 7, 8 };
var filtered = list.Zip(Enumerable.Range(0, list.Length), Tuple.Create)
.Where((x, i) => i == 0 || list[i - 1] != x.Item1 - 1).ToArray();
var result = filtered.Select((x, i) => i == filtered.Length - 1
? Tuple.Create(x.Item1, list.Length - x.Item2)
: Tuple.Create(x.Item1, filtered[i + 1].Item2 - x.Item2));
foreach (var t in result)
{
Console.WriteLine(t);
}
Run Code Online (Sandbox Code Playgroud)
这导致
(1, 3)
(5, 1)
(7, 2)
Run Code Online (Sandbox Code Playgroud)