是否可以使用LINQ检查列表中的所有数字是否单调递增?

我很感兴趣,如果在LINQ中有一种方法来检查列表中的所有数字是否单调增加?

List list1 = new List() { 1, 2, 3, 4 }; Debug.Assert(list1.IsIncreasingMonotonically() == true); List list2 = new List() { 1, 2, 100, -5 }; Debug.Assert(list2.IsIncreasingMonotonically() == false); 

我问的原因是我想知道将列表中的元素与其前一个元素进行比较的技术,这是我在使用LINQ时从未理解过的。

C#中的完成示例类

根据下面@Servy官方回答,这是我现在使用的完整课程。 它为您的项目添加扩展方法,以检查列表是单调增加/减少还是严格单调增加/减少。 我正在尝试习惯一种函数式编程风格,这是一种很好的学习方法。

 using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyHelper { ///  /// Classes to check if a list is increasing or decreasing monotonically. See: /// http://stackoverflow.com/questions/14815356/is-it-possible-to-use-linq-to-check-if-all-numbers-in-a-list-are-increasing-mono#14815511 /// Note the difference between strictly monotonic and monotonic, see: /// http://en.wikipedia.org/wiki/Monotonic_function ///  public static class IsMonotonic { ///  /// Returns true if the elements in the are increasing monotonically. ///  /// Type of elements in the list. /// List we are interested in. /// True if all of the the elements in the list are increasing monotonically. public static bool IsIncreasingMonotonically(this List list) where T : IComparable { return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b)  b); } ///  /// Returns true if the elements in the are increasing strictly monotonically. ///  /// Type of elements in the list. /// List we are interested in. /// True if all of the the elements in the list are increasing monotonically. public static bool IsIncreasingStrictlyMonotonically(this List list) where T : IComparable { return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b)  b); } ///  /// Returns true if the elements in the are decreasing monotonically. ///  /// Type of elements in the list. /// List we are interested in. /// True if all of the the elements in the list are decreasing monotonically. public static bool IsDecreasingMonotonically(this List list) where T : IComparable { return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) >= 0).All(b => b); } ///  /// Returns true if the elements in the are decreasing strictly monotonically. ///  /// Type of elements in the list. /// List we are interested in. /// True if all of the the elements in the list are decreasing strictly monotonically. public static bool IsDecreasingStrictlyMonotonically(this List list) where T : IComparable { return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) > 0).All(b => b); } ///  /// Returns true if the elements in the are increasing monotonically. ///  /// Type of elements in the list. /// List we are interested in. /// True if all of the the elements in the list are increasing monotonically. public static bool IsIncreasingMonotonicallyBy(this List list, Func x) where T : IComparable { return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b)  b); } public static void UnitTest() { { List list = new List() { 1, 2, 3, 4 }; Debug.Assert(list.IsIncreasingMonotonically() == true); Debug.Assert(list.IsIncreasingStrictlyMonotonically() == true); Debug.Assert(list.IsDecreasingMonotonically() == false); Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false); } { List list = new List() { 1, 2, 100, -5 }; Debug.Assert(list.IsIncreasingMonotonically() == false); Debug.Assert(list.IsIncreasingStrictlyMonotonically() == false); Debug.Assert(list.IsDecreasingMonotonically() == false); Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false); } { List list = new List() {1, 1, 2, 2, 3, 3, 4, 4}; Debug.Assert(list.IsIncreasingMonotonically() == true); Debug.Assert(list.IsIncreasingStrictlyMonotonically() == false); Debug.Assert(list.IsDecreasingMonotonically() == false); Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false); } { List list = new List() { 4, 3, 2, 1 }; Debug.Assert(list.IsIncreasingMonotonically() == false); Debug.Assert(list.IsIncreasingStrictlyMonotonically() == false); Debug.Assert(list.IsDecreasingMonotonically() == true); Debug.Assert(list.IsDecreasingStrictlyMonotonically() == true); } { List list = new List() { 4, 4, 3, 3, 2, 2, 1, 1 }; Debug.Assert(list.IsIncreasingMonotonically() == false); Debug.Assert(list.IsIncreasingStrictlyMonotonically() == false); Debug.Assert(list.IsDecreasingMonotonically() == true); Debug.Assert(list.IsDecreasingStrictlyMonotonically() == false); } } } } 

 public static bool IsIncreasingMontonically(List list) where T : IComparable { return list.Zip(list.Skip(1), (a, b) => a.CompareTo(b) <= 0) .All(b => b); } 

请注意,这会迭代序列两次。 对于List ,这根本不是问题,对于IEnumerableIQueryable来说可能是坏的,所以在将List更改为IEnumerable之前要小心。

您是否不使用OrderBy()订购列表并将它们与原始列表进行比较? 如果它们是相同的那么它会给你的答案伪说话:

 var increasing = orignalList.OrderBy(m=>m.value1).ToList(); var decreasing = orignalList.OrderByDescending(m=>m.value1).ToList(); var mono = (originalList == increasing || originalList == decreasing) 

使用循环! 它简短,快速且易读。 除了Servy的答案之外,该线程中的大多数解决方案都不必要地慢(排序需要’n log n’时间)。

 // Test whether a sequence is strictly increasing. public bool IsIncreasing(IEnumerable list) { bool initial = true; double last = Double.MinValue; foreach(var x in list) { if (!initial && x <= last) return false; initial = false; last = x; } return true; } 

例子

  1. IsIncreasing(new List{1,2,3})返回True
  2. IsIncreasing(new List{1,3,2})返回False

通过使用Enumerable.Aggregate方法:

 list1.Aggregate((a, i) => a > i ? double.MaxValue : i) != double.MaxValue; 

这是一个可以工作的单线程

 var isIncreasing = list.OrderBy(x => x).SequenceEqual(list); 

或者如果你想要表演,这里只有一行,只会遍历列表一次,并且一旦到达一个不按顺序的元素就退出:

 var isIncreasing = !list.SkipWhile((x, i) => i == 0 || list[i - 1] <= x).Any(); 

如果要检查列表是否始终从索引增加到索引:

 IEnumerable list = new List() { 1, 2, 3, 4, 5, 6, 7, 10 }; bool allIncreasing = !list .Where((i, index) => index > 0 && list.ElementAt(index - 1) >= i) .Any(); 

演示

但在我看来,在这种情况下,简单的循环会更具可读性。

考虑如下所示的实现,它只枚举给定的IEnumerable一次。 枚举可能会产生副作用,如果可能的话,调用者通常会期望单个传递。

 public static bool IsIncreasingMonotonically( this IEnumerable _this) where T : IComparable { using (var e = _this.GetEnumerator()) { if (!e.MoveNext()) return true; T prev = e.Current; while (e.MoveNext()) { if (prev.CompareTo(e.Current) > 0) return false; prev = e.Current; } return true; } } 
 public static class EnumerableExtensions { private static bool CompareAdjacentElements(this IEnumerable source, Func comparison) { using (var iterator = source.GetEnumerator()) { if (!iterator.MoveNext()) throw new ArgumentException("The input sequence is empty", "source"); var previous = iterator.Current; while (iterator.MoveNext()) { var next = iterator.Current; if (comparison(previous, next)) return false; previous = next; } return true; } } public static bool IsSorted(this IEnumerable source) where TSource : IComparable { return CompareAdjacentElements(source, (previous, next) => previous.CompareTo(next) > 0); } public static bool IsSorted(this IEnumerable source, Comparison comparison) { return CompareAdjacentElements(source, (previous, next) => comparison(previous, next) > 0); } public static bool IsStrictSorted(this IEnumerable source) where TSource : IComparable { return CompareAdjacentElements(source, (previous, next) => previous.CompareTo(next) >= 0); } public static bool IsStrictSorted(this IEnumerable source, Comparison comparison) { return CompareAdjacentElements(source, (previous, next) => comparison(previous, next) >= 0); } }