首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Linq在列表中查找连续项

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

Stack Overflow用户
提问于 2011-08-18 18:41:19
回答 4查看 6.2K关注 0票数 7

假设我有以下整数数组:

代码语言:javascript
复制
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 };

我如何编写一个Linq查询,查找3个连续的元素,比如说大于10?另外,如果我可以指定第一、第二、第三组这样的元素,那就太好了。

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

如果我指定要连续三个元素的第二组,查询应该返回给我第二组。

谢谢。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-08-18 18:48:06

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

代码语言:javascript
复制
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);
            }
        }
    }
}

输出:

代码语言:javascript
复制
12,15,17
23,25,27
67,33,13 

要获得第二组,请更改:

代码语言:javascript
复制
var consecutiveGroups = numbers.FindConsecutiveGroups((x) => x > 10, 3);

至:

代码语言:javascript
复制
var consecutiveGroups = numbers.FindConsecutiveGroups((x) => x > 10, 3).Skip(1).Take(1);

在我们的生产使用中对此进行微调之后,更新2,随着数字数组中项的计数增加,下面的实现要快得多。

代码语言:javascript
复制
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>();
        }
    }
}
票数 12
EN

Stack Overflow用户

发布于 2011-08-18 18:56:10

代码语言:javascript
复制
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 numbersQuery = numbers.Select((x, index) => new { Index = index, Value = x});

var query = from n in numbersQuery
            from n2 in numbersQuery.Where(x => n.Index == x.Index - 1).DefaultIfEmpty()
            from n3 in numbersQuery.Where(x => n.Index == x.Index - 2).DefaultIfEmpty()
            where n.Value > 10
            where n2 != null && n2.Value > 10
            where n3 != null && n3.Value > 10
            select new
            {
              Value1 = n.Value,
              Value2 = n2.Value,
              Value3 = n3.Value
            };

为了指定哪个组,可以调用Skip方法

代码语言:javascript
复制
query.Skip(1)
票数 3
EN

Stack Overflow用户

发布于 2011-08-18 21:10:41

为什么不试试这个扩展方法呢?

代码语言:javascript
复制
public static IEnumerable<IEnumerable<T>> Consecutives<T>(this IEnumerable<T> numbers, int ranges, Func<T, bool> predicate)
{
    IEnumerable<T> ordered = numbers.OrderBy(a => a).Where(predicate);
    decimal n = Decimal.Divide(ordered.Count(), ranges);
    decimal max = Math.Ceiling(n); // or Math.Floor(n) if you want
    return from i in Enumerable.Range(0, (int)max)
           select ordered.Skip(i * ranges).Take(ranges);
}

唯一需要改进的是对Count方法的调用,因为这会导致numbers的枚举(因此查询失去了它的惰性)。

无论如何,我确信这可以满足您的linqness要求。

编辑:,或者这是较少的单词版本(它不使用计数方法):

代码语言:javascript
复制
public static IEnumerable<IEnumerable<T>> Consecutives<T>(this IEnumerable<T> numbers, int ranges, Func<T, bool> predicate)
{
    var ordered = numbers.OrderBy(a => a);
    return ordered.Where(predicate)
                  .Select((element, i) => ordered.Skip(i * ranges).Take(ranges))
                  .TakeWhile(Enumerable.Any);
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7112435

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档