首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从给定的列表中检测至少3个序列号的序列

从给定的列表中检测至少3个序列号的序列
EN

Stack Overflow用户
提问于 2010-10-02 06:11:59
回答 9查看 15K关注 0票数 25

我有一个号码清单,例如21,4,7,9,12,22,17,8,2,20,23

我希望能够选择序列序列(至少3项长度),所以从上面的例子中,它将是7,8,9和20,21,22,23。

我曾经玩过一些丑陋的、杂乱无章的功能,但我想知道是否有一种简洁的LINQ方法来实现它。

有什么建议吗?

更新:

非常感谢你的回复,非常感谢。我目前正在与他们所有的发挥,看看哪一个将最好地集成到我们的项目。

EN

回答 9

Stack Overflow用户

发布于 2010-10-02 06:20:26

我突然想到,你应该做的第一件事就是订购这份清单。然后,它只是一个问题,通过它,记住你的当前序列的长度,并检测它何时结束。老实说,我怀疑一个简单的foreach循环将是最简单的方法--我不能马上想到任何类似LINQ的奇妙的方法。如果你真的想要的话,你当然可以在迭代器块中这样做,但是要记住,命令列表从一开始就意味着你已经有了合理的“预先”成本。所以我的解决方案应该是这样的:

代码语言:javascript
复制
var ordered = list.OrderBy(x => x);
int count = 0;
int firstItem = 0; // Irrelevant to start with
foreach (int x in ordered)
{
    // First value in the ordered list: start of a sequence
    if (count == 0)
    {
        firstItem = x;
        count = 1;
    }
    // Skip duplicate values
    else if (x == firstItem + count - 1)
    {
        // No need to do anything
    }
    // New value contributes to sequence
    else if (x == firstItem + count)
    {
        count++;
    }
    // End of one sequence, start of another
    else
    {
        if (count >= 3)
        {
            Console.WriteLine("Found sequence of length {0} starting at {1}",
                              count, firstItem);
        }
        count = 1;
        firstItem = x;
    }
}
if (count >= 3)
{
    Console.WriteLine("Found sequence of length {0} starting at {1}",
                      count, firstItem);
}

编辑:好吧,我只是想到了一种更多的LINQ风格的做事方式。我现在没有时间完全实现它,但是:

  • 命令序列
  • 使用类似SelectWithPrevious (可能更好的名称为SelectConsecutive)来获取连续的元素对,
  • 使用选择的重载,其中包括获取元组的索引(索引,当前,如果任何项目(当前=前一个+ 1)被认为是序列(特例previous)
  • Filter )的开始(特殊情况index=0),则
  • 将在结果中使用SelectWithPrevious获取两个起始点之间的序列长度(从previous)
  • Filter中减去一个索引,将长度小于3

的任何序列减去)。

我怀疑您需要在有序的序列上连接int.MinValue,以确保最终的项被正确地使用。

编辑:好的,我已经实现了这一点。是关于我能想到做这个的LINQiest方法.我使用null值作为"sentinel“值来强制开始和结束序列--有关更多细节,请参见注释。

总的来说,我不推荐这个解决方案。这是很难让你的头,虽然我很有信心它是正确的,它花了我一段时间来思考可能的一个错误,等等。这是一个有趣的航程,你可以用LINQ.还有你可能不该做的事。

哦,请注意,我已经把“最小长度3”部分推到了调用方--当您有这样的一个元组序列时,单独过滤它是比较干净的,IMO。

代码语言:javascript
复制
using System;
using System.Collections.Generic;
using System.Linq;

static class Extensions
{
    public static IEnumerable<TResult> SelectConsecutive<TSource, TResult>
        (this IEnumerable<TSource> source,
         Func<TSource, TSource, TResult> selector)
    {
        using (IEnumerator<TSource> iterator = source.GetEnumerator())
        {
           if (!iterator.MoveNext())
           {
               yield break;
           }
           TSource prev = iterator.Current;
           while (iterator.MoveNext())
           {
               TSource current = iterator.Current;
               yield return selector(prev, current);
               prev = current;
           }
        }
    }
}

class Test
{
    static void Main()
    {
        var list = new List<int> {  21,4,7,9,12,22,17,8,2,20,23 };

        foreach (var sequence in FindSequences(list).Where(x => x.Item1 >= 3))
        {
            Console.WriteLine("Found sequence of length {0} starting at {1}",
                              sequence.Item1, sequence.Item2);
        }
    }

    private static readonly int?[] End = { null };

    // Each tuple in the returned sequence is (length, first element)
    public static IEnumerable<Tuple<int, int>> FindSequences
         (IEnumerable<int> input)
    {
        // Use null values at the start and end of the ordered sequence
        // so that the first pair always starts a new sequence starting
        // with the lowest actual element, and the final pair always
        // starts a new one starting with null. That "sequence at the end"
        // is used to compute the length of the *real* final element.
        return End.Concat(input.OrderBy(x => x)
                               .Select(x => (int?) x))
                  .Concat(End)
                  // Work out consecutive pairs of items
                  .SelectConsecutive((x, y) => Tuple.Create(x, y))
                  // Remove duplicates
                  .Where(z => z.Item1 != z.Item2)
                  // Keep the index so we can tell sequence length
                  .Select((z, index) => new { z, index })
                  // Find sequence starting points
                  .Where(both => both.z.Item2 != both.z.Item1 + 1)
                  .SelectConsecutive((start1, start2) => 
                       Tuple.Create(start2.index - start1.index, 
                                    start1.z.Item2.Value));
    }
}
票数 28
EN

Stack Overflow用户

发布于 2010-10-02 09:49:44

我认为我的解决方案更优雅、更简单,因此更容易验证为正确:

代码语言:javascript
复制
/// <summary>Returns a collection containing all consecutive sequences of
/// integers in the input collection.</summary>
/// <param name="input">The collection of integers in which to find
/// consecutive sequences.</param>
/// <param name="minLength">Minimum length that a sequence should have
/// to be returned.</param>
static IEnumerable<IEnumerable<int>> ConsecutiveSequences(
    IEnumerable<int> input, int minLength = 1)
{
    var results = new List<List<int>>();
    foreach (var i in input.OrderBy(x => x))
    {
        var existing = results.FirstOrDefault(lst => lst.Last() + 1 == i);
        if (existing == null)
            results.Add(new List<int> { i });
        else
            existing.Add(i);
    }
    return minLength <= 1 ? results :
        results.Where(lst => lst.Count >= minLength);
}

优于其他解决方案:

  • 它可以找到重叠的序列。
  • 它是正确的可重用和文档化的。
  • I没有发现任何bug ;-)
票数 4
EN

Stack Overflow用户

发布于 2010-10-02 07:18:02

下面是如何以"LINQish“的方式解决问题:

代码语言:javascript
复制
int[] arr = new int[]{ 21, 4, 7, 9, 12, 22, 17, 8, 2, 20, 23 };
IOrderedEnumerable<int> sorted = arr.OrderBy(x => x);
int cnt = sorted.Count();
int[] sortedArr = sorted.ToArray();
IEnumerable<int> selected = sortedArr.Where((x, idx) =>
    idx <= cnt - 3 && sortedArr[idx + 1] == x + 1 && sortedArr[idx + 2] == x + 2);
IEnumerable<int> result = selected.SelectMany(x => new int[] { x, x + 1, x + 2 }).Distinct();

Console.WriteLine(string.Join(",", result.Select(x=>x.ToString()).ToArray()));

由于数组的复制和重构,这种解决方案--当然--并不像传统的循环解决方案那样有效。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3844611

复制
相关文章

相似问题

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