【问题标题】:How to check if the sequence of ints has even and odd numbers alternating using LINQ, C#如何使用LINQ,C#检查整数序列是否具有偶数和奇数交替
【发布时间】:2021-02-28 11:31:14
【问题描述】:

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

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

有没有办法检查它是否有 alternating oddeven 数字(如上面的示例:if 一个如果它们是偶数,那么下一个必须是奇数,反之亦然)?

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

【问题讨论】:

    标签: c# algorithm linq extension-methods


    【解决方案1】:

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

      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# 可以返回负余数(例如-1 % 2);我们不希望对此进行额外检查,所以让我们使用绝对值
    4. 但是,我们可以在最终的Aggregate 中利用此效果(-1 % 2 == -1

    Extension Method 解决方案我希望更容易理解:

      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;
      }
    

    注意,循环解决方案(扩展方法)更有效:当模式不满足时,它会返回false立即

    【讨论】:

    • 优雅的解决方案,尽管值得注意的是,使用标准 LINQ 方法的建议将在给出答案之前遍历整个集合,即使前两项违反了交替规则。
    【解决方案2】:

    您可以通过这种方式使用 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
    }
    

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

    【讨论】:

    • 可能的反例示例:new List&lt;int&gt;() { 8, 1, 2, 7};,预期 true(奇数和偶数是交替),实际 false。请注意,现在偶数在偶数位置,而奇数在奇数位置
    • @DmitryBychenko 我在答案中添加了假设。感谢您的通知
    【解决方案3】:

    您可以使用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;
    

    【讨论】:

      猜你喜欢
      • 2021-11-17
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 2014-03-04
      • 2013-06-09
      • 1970-01-01
      • 2010-12-02
      相关资源
      最近更新 更多