如何使用 LINQ、C# 检查整数序列是否交替出现偶数和奇数

How to check if the sequence of ints has even and odd numbers alternating using LINQ, C#

假设我在 c# 中有一个整数列表,如下所示:

List<int> numbers = new List<int>() { 1, 2, 7, 20, 3 };

有没有办法检查它有 alternating oddeven 数字它(如上例所示:如果 one 如果它们是 even 那么 next 必须是 奇数 反之亦然)?

我知道在循环中检查它很简单,但我正在尝试仅使用 LINQ 和扩展方法来实现它。

我们来分析一下问题。交替奇偶校验是什么意思?

  index : value : value + index
  ------------------------------
      0 :     1 : 1 - note, all sums are odd
      1 :     2 : 3
      2 :     7 : 9
         ....

  index : value : value + index
  ------------------------------
      0 :     2 : 2 - note, all sums are even
      1 :     1 : 2
      2 :     6 : 8
         ....

如您所见(并且您可以轻松证明)交替奇偶校验意味着 index + value 总和是 all oddall even。让我们在 Linq 的帮助下检查一下:

  List<int> numbers = new List<int>() { 1, 2, 7, 20, 3, 79 };

  bool result = numbers
    .DefaultIfEmpty()
    .Select((item, index) => Math.Abs((long)item + (long)index))
    .Aggregate((s, a) => s % 2 == a % 2 ? s % 2 : -1) >= 0;

实施注意事项:

  1. DefaultIfEmpty() - 空序列具有交替的所有(全零)值;然而,Aggregate 没有任何聚合并抛出异常。让我们把空序列变成一个元素序列。
  2. (long)为了防止整数溢出int.MaxValue + index可以超出int范围)
  3. Math.Abs:c#可以return负余数(例如-1 % 2);我们不想对此进行额外检查,所以让我们使用绝对值
  4. 然而,我们可以在最后的 Aggregate
  5. 中利用这个效果 (-1 % 2 == -1)

我希望更容易理解的扩展方法解决方案:

  public static bool IsAlternating(this IEnumerable<int> source) {
    if (null == source)
      throw new ArgumentNullException(nameof(source));

    bool expectedZero = false;
    bool first = true;

    foreach (int item in source) {
      int actual = item % 2;

      if (first) {
        first = false;
        expectedZero = actual == 0;
      } 
      else if (actual == 0 && !expectedZero || actual != 0 && expectedZero) 
        return false;  

      expectedZero = !expectedZero;
    } 

    return true;
  }

请注意,循环解决方案(扩展方法)更有效:它returns false 立即 当模式不符合时。

你可以用这种方式使用 LINQ。您可以检查添加位置是否有最后一个偶数项或偶数位是否有奇数项。

List<int> numbers = new List<int>() { 1, 2, 7, 20, 3 };
var temp = numbers.Where((x, i) => (i % 2 == 0 && x % 2 == 0) || (i % 2 == 1 && x % 2 == 1)).Take(1);
int count = temp.Count();
if(count == 0)
{
    //true
}
else
{
    //false
}

注意:假设您希望偶数出现在偶数位,奇数出现在奇数位。

您可以使用 Aggregate 来确定序列是否交替。

假设如果有 0 个或 1 个元素,则结果为真。 您可以根据需要修改此逻辑。

基于此可以创建一个扩展方法:

    public static bool IsAlternatingParitySequenceVerbose(this IEnumerable<int> col)
    {
        // state:
        // -1 - sequence is not alternating
        //  0 - even
        //  1 - odd

        if (!col.Any())
            return true;

        //check if first value is even
        var firstState = Math.Abs(col.First() % 2);

        var IsAlternating = col.Skip(1).Aggregate(firstState, (state, val) =>
        {
            if (state == -1)
                return -1;

            var current = Math.Abs(val % 2);
            if (current == state)
                return -1;

            return current;
        });

        return IsAlternating != -1;
    }

然后用它做一个单行:

    public static bool IsAlternatingParitySequence(this IEnumerable<int> col) =>
        !col.Any()
        || col.Skip(1).Aggregate(Math.Abs(col.First() % 2), (state, val) =>
                state == -1
                    ? -1
                    : Math.Abs(val % 2) is var current && current == state
                    ? -1
                    : current
            ) != -1;