使用Linq在列表中查找连续项

Ran*_*der 5 linq

假设我有以下整数数组:

int[] numbers = { 1, 6, 4, 10, 9, 12, 15, 17, 8, 3, 20, 21, 2, 23, 25, 27, 5, 67,33, 13, 8, 12, 41, 5 };
Run Code Online (Sandbox Code Playgroud)

我怎么能写一个Linq查询找到3 个连续的元素,比如大于10?此外,如果我能指定我想要说这些元素的第一,第二,第三等组,那将是很好的.

例如,Linq查询应该能够识别:12,15,17作为第一组连续元素23,25,27作为第二组67,33,13作为第三组

如果我指定我想要第二组3个连续元素,查询应该返回给我第二组.

谢谢.

Jim*_*Jim 9

更新:虽然技术上不像帕特里克在评论中指出的"linq查询",但这个解决方案是可重用的,灵活的和通用的.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication32
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] numbers = { 1, 6, 4, 10, 9, 12, 15, 17, 8, 3, 20, 21, 2, 23, 25, 27, 5, 67,33, 13, 8, 12, 41, 5 };

            var consecutiveGroups = numbers.FindConsecutiveGroups((x) => x > 10, 3);

            foreach (var group in consecutiveGroups)
            {
                Console.WriteLine(String.Join(",", group));
            }
        }        
    }

    public static class Extensions
    {
        public static IEnumerable<IEnumerable<T>> FindConsecutiveGroups<T>(this IEnumerable<T> sequence, Predicate<T> predicate, int count)
        {
            IEnumerable<T> current = sequence;

            while (current.Count() > count)
            {
                IEnumerable<T> window = current.Take(count);

                if (window.Where(x => predicate(x)).Count() >= count)
                    yield return window;

                current = current.Skip(1);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

12,15,17
23,25,27
67,33,13 
Run Code Online (Sandbox Code Playgroud)

要获得第二组,请更改:

var consecutiveGroups = numbers.FindConsecutiveGroups((x) => x > 10, 3);
Run Code Online (Sandbox Code Playgroud)

至:

var consecutiveGroups = numbers.FindConsecutiveGroups((x) => x > 10, 3).Skip(1).Take(1);
Run Code Online (Sandbox Code Playgroud)

更新2在我们的生产用途中调整后,随着数字数组中项目数量的增加,以下实现速度要快得多.

public static IEnumerable<IEnumerable<T>> FindConsecutiveGroups<T>(this IEnumerable<T> sequence, Predicate<T> predicate, int sequenceSize)
{
    IEnumerable<T> window = Enumerable.Empty<T>();

    int count = 0;

    foreach (var item in sequence)
    {
        if (predicate(item))
        {
            window = window.Concat(Enumerable.Repeat(item, 1));
            count++;

            if (count == sequenceSize)
            {
                yield return window;
                window = window.Skip(1);
                count--;
            }
        }
        else
        {
            count = 0;
            window = Enumerable.Empty<T>();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)