检查List<Int32>值是否连续

24
List<Int32> dansConList = new List<Int32>();
dansConList[0] = 1;
dansConList[1] = 2;
dansConList[2] = 3;

List<Int32> dansRandomList = new List<Int32>();
dansRandomList[0] = 1;
dansRandomList[1] = 2;
dansRandomList[2] = 4;

我需要一个方法,当评估上述列表时,将基于以下事实对dansConList返回true(因为它的值具有连续数字序列),并对dansRandomList返回false(因为它缺少值3)。

如果可能的话,最好使用LINQ。

我尝试过的:

  • 为了达到最终目标,我使用了一个for循环,并与“i”(循环计数器)进行比较来评估这些值,但如上所述,我想使用LINQ。

3
为什么要使用 Linq?Linq 会带来性能损失,但它的好处在于程序维护和抽象化方面,特别是对于 LinqToSql 和 EF 中的数据库。我不明白除了追随 2008 年流行词汇趋势之外,你在这里使用它有何用处。 - Dai
1
使用LINQ没有非常简洁的方法,因为它会将每个项目单独处理。你可以使用Aggregate做一些事情,但这样做会很丑陋。你可以使用Enumerable.Range()和Except来检查列表是否包含两个整数之间的所有项。但是,要检查连续性,似乎for循环是最好的选择。 - Kieren Johnstone
请看这篇帖子:http://bugsquash.blogspot.se/2010/01/grouping-consecutive-integers-in-c.html - Jocke
哦,等等,实际上我有一个方法... - Kieren Johnstone
1
@DeeMac,你想得到什么结果:{1, 3, 2}(包含连续数字,但顺序错误){3, 2}(连续但降序),还是{3, 2, 3} - CodesInChaos
显示剩余6条评论
13个回答

69

这是一个一行代码的解决方案,仅迭代到第一个非连续元素:

bool isConsecutive = !myIntList.Select((i,j) => i-j).Distinct().Skip(1).Any();

更新:以下是一些示例,说明这个如何工作:

Input is { 5, 6, 7, 8 }
Select yields { (5-0=)5, (6-1=)5, (7-2=)5, (8-3=)5 }
Distinct yields { 5, (5 not distinct, 5 not distinct, 5 not distinct) }
Skip yields { (5 skipped, nothing left) }
Any returns false
Input is { 1, 2, 6, 7 }
Select yields { (1-0=)1, (2-1=)1, (6-2=)4, (7-3=)4 } *
Distinct yields { 1, (1 not distinct,) 4, (4 not distinct) } *
Skip yields { (1 skipped,) 4 }
Any returns true

* 由于 Any 在找到第一个 4 后就会停止,所以 Select 不会输出第二个 4,Distinct 也不会检查它。


1
@KierenJohnstone 是的,它确实是这样,"value"只是一个非零值,因此需要使用distinct和skip...算了。 :P - Cameron MacFarland
14
+1 利用 Linq 进行创造性编程,也许会牺牲可读性 :) - Johan Larsson
1
“Distinct” 将第一个值添加到哈希集合中,然后生成它;尝试添加第二个值,如果它不在集合中,则生成它;尝试添加第三个值等。 它不必在可以开始生成项目之前消耗整个输入。 - Rawling
1
假设你有 { 1, 2, 3, 2, 3, 4 }... 当你看到 1 时,你可以返回 12 返回 23 返回 3。然后你看到第二个 23,不返回它们,因为它们不是唯一的。然后你返回 4 - Rawling
2
@ChrisNevill 这是Select这个重载版本(通过将元素的索引合并到新形式中,将序列的每个元素投影到一个新形式中)。请注意,参数是Func<TSource, Int32, TResult>-接受源项和整数并返回结果项。 - Rawling
显示剩余7条评论

11
var result = list
    .Zip(list.Skip(1), (l, r) => l + 1 == r)
    .All(t => t);

另一个被低估的答案。太棒了。我猜它被低估是因为大多数人不知道Zip函数。 - Sinan ILYAS

10
var min = list.Min();
var max = list.Max();
var all = Enumerable.Range(min, max - min + 1);
return list.SequenceEqual(all);

2
@Kieren Johnstone 应该使用 Enumerable.Range(min, max-min)。 - user1793607
3
我对此有问题的是它枚举了原始列表三次,一次用于最小值,一次用于最大值,还有一次用于比较。 - Cameron MacFarland
@user1793607 - 不,最大值和最小值意味着如果应该有1个,则计数范围为0。 - Kieren Johnstone
@CameronMacFarland - 是的,在这里应用LINQ是一个糟糕的技术。每次都是for循环获胜。 - Kieren Johnstone
看起来不错。我还有一个问题 - 使用带有循环计数器的 for 循环会更好吗?我的意思是性能方面。 - besworland
显示剩余6条评论

8
你可以使用这个扩展方法:
public static bool IsConsecutive(this IEnumerable<int> ints )
{
    //if (!ints.Any())
    //    return true; //Is empty consecutive?
    // I think I prefer exception for empty list but I guess it depends
    int start = ints.First();
    return !ints.Where((x, i) => x != i+start).Any();
}

使用方法如下:

[Test]
public void ConsecutiveTest()
{
    var ints = new List<int> {1, 2, 4};
    bool isConsecutive = ints.IsConsecutive();
}

尝试使用 Enumerable.Empty<int>()。嘭。 - CodesInChaos
是的,没错。我猜这只是个人口味问题,但如果传递 Enumerable.Empty<int>(),我认为应该加上一个例外。我需要改变吗? - Johan Larsson
我更喜欢在这里使用带有索引参数的Where谓词,而不是我的方法...我不知道它的存在! - Kieren Johnstone

4
扩展方法:
public static bool IsConsecutive(this IEnumerable<int> myList)
{
    return myList.SequenceEqual(Enumerable.Range(myList.First(), myList.Last()));
}

使用方法:

bool isConsecutive = dansRandomList.IsConsecutive();

@davenewza 如果列表没有排序,就不行。 - Alex Wiese
但是我理解列表必须有序?值需要“连续”。 - Dave New
是的,但您还没有检查它是否为真。 - Alex Wiese
你假设它是连续的,而不是测试它是否连续。 - Kieren Johnstone
myList.SequenceEqual(Enumerable.Range(myList.First(), myList.Count())); 这个代码可以正常工作,即使输入的列表不以1开头。 - Suresh Kumar Veluswamy

1

注意:如果为空则返回true。

var list = new int[] {-1,0,1,2,3};
var isConsecutive = list.Select((n,index) => n == index+list.ElementAt(0)).All (n => n);

0

这是另一个。它支持{1,2,3,4}和{4,3,2,1}。它测试连续数字之间的差是否等于1或-1。

Function IsConsecutive(ints As IEnumerable(Of Integer)) As Boolean
    If ints.Count > 1 Then
        Return Enumerable.Range(0, ints.Count - 1).
            All(Function(r) ints(r) + 1 = ints(r + 1) OrElse ints(r) - 1 = ints(r + 1))
    End If

    Return False
End Function

它将1、2、1评估为true,这是不正确的。 - Antonín Lejsek

0

虽然这是一个老问题,但是有一个简单的方法可以使用一些简单的代数来解决。

这仅适用于您的整数从1开始的情况。

public bool AreIntegersConsecutive(List<int> integers)
{
    var sum = integers.Sum();
    var count = integers.Count();
    var expectedSum = (count * (count + 1)) / 2;

    return expectedSum == sum;
}

2
说到简单,我想知道为什么没有人提出 list.Max() - list.Min() - list.Count == -1 - Gert Arnold

0

为了检查系列中是否包含连续数字,您可以使用以下代码:

示例

isRepeatable(121878999, 2);

结果 = 真

由于9重复了两次,其中upto是系列中的次数

isRepeatable(37302293, 3)

结果 = 假

由于没有连续出现3次的数字

static bool isRepeatable(int num1 ,int upto)
    {
        List<int> myNo = new List<int>();
        int previous =0;
        int series = 0;
        bool doesMatch = false;
        var intList = num1.ToString().Select(x => Convert.ToInt32(x.ToString())).ToList();
        for (int i = 0; i < intList.Count; i++)
        {
            if (myNo.Count==0)
            {
                myNo.Add(intList[i]);
                previous = intList[i];
                series += 1;
            }
            else
            {
                if (intList[i]==previous)
                {
                    series += 1;
                    if (series==upto)
                    {
                        doesMatch = true;
                        break;
                    }
                }
                else
                {
                    myNo = new List<int>();
                    previous = 0;
                    series = 0;
                }
            }
           
        }

        return doesMatch;

    }

0
// 1 | 2 | 3 | 4 | _
// _ | 1 | 2 | 3 | 4
//   | 1 | 1 | 1 |    => must be 1 (or 2 for even/odd consecutive integers)

var numbers = new List<int>() { 1, 2, 3, 4, 5 };
const step = 1; // change to 2 for even and odd consecutive integers

var isConsecutive = numbers.Skip(1)
   .Zip(numbers.SkipLast(1))
   .Select(n => {
       var diff = n.First - n.Second;
       return (IsValid: diff == step, diff);
   })
   .Where(diff => diff.IsValid)
   .Distinct()
   .Count() == 1;

或者我们可以写得更短,但可读性会降低:

var isConsecutive = numbers.Skip(1)
   .Zip(numbers.SkipLast(1), (l, r) => (IsValid: (l-r == step), l-r))
   .Where(diff => diff.IsValid)
   .Distinct()
   .Count() == 1;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接