C# 如果IEnumerable已排序,则识别的方法

C# 如果IEnumerable已排序,则识别的方法,c#,list,sorting,C#,List,Sorting,我使用这个扩展方法来检查是否对任何类型的列表进行了排序 public static bool IsSorted<T>(this IEnumerable<T> input) { IEnumerable<T> expectedListASC = input.OrderBy(x => x); IEnumerable<T> expectedListDESC = input.OrderByDescending(x => x);

我使用这个扩展方法来检查是否对任何类型的列表进行了排序

public static bool IsSorted<T>(this IEnumerable<T> input)
{
    IEnumerable<T> expectedListASC = input.OrderBy(x => x);
    IEnumerable<T> expectedListDESC = input.OrderByDescending(x => x);
    return expectedListASC.SequenceEqual(input) || expectedListDESC.SequenceEqual(input);
}
publicstaticbool已排序(此IEnumerable输入)
{
IEnumerable expectedListASC=input.OrderBy(x=>x);
IEnumerable expectedListDESC=input.OrderByDescending(x=>x);
返回expectedListASC.SequenceEqual(输入)| | expectedListDESC.SequenceEqual(输入);
}

但对于大型列表,这需要时间。有没有更有效的方法来获得相同的结果?

类似的方法应该会奏效:

public static bool IsSorted<T>(IEnumerable<T> input)
{
    if (input is IOrderedEnumerable<T>)
    {
        return true;
    }

    var comparer = Comparer<T>.Default;
    T previous = default(T);
    bool previousSet = false;
    bool? comparisonOrder = null;
    foreach (var value in input)
    {
        if (!previousSet)
        {
            previous = value;
            previousSet = true;
        }
        else
        {
            int comparisonResult = comparer.Compare(previous, value);
            if (comparisonResult != 0)
            {
                if (!comparisonOrder.HasValue)
                {
                    comparisonOrder = comparisonResult > 0;
                }
                else if (comparisonResult > 0 != comparisonOrder)
                {
                    return false;
                }
            }
            previous = value;
        }
    }
    return true;
}
公共静态布尔值已排序(IEnumerable输入)
{
if(输入为IOrderedEnumerable)
{
返回true;
}
var comparer=comparer.Default;
T先前=默认值(T);
bool-previousSet=false;
bool?comparisonoder=null;
foreach(输入中的var值)
{
如果(!previousSet)
{
先前=值;
previousSet=true;
}
其他的
{
int comparisonResult=comparer.Compare(上一个,值);
如果(比较结果!=0)
{
如果(!comparisonoder.HasValue)
{
ComparisonNorder=comparisonResult>0;
}
else if(comparisonResult>0!=comparisonnorder)
{
返回false;
}
}
先前=值;
}
}
返回true;
}
它在跟踪上一个项目的同时遍历每个项目,然后使用默认比较器(如
.OrderBy()
will)检查它们是否已排序。为了允许在任意方向上检查排序,我存储第一次非零比较的结果,并将其用作检查点

正如评论中已经指出的,并非所有的
IEnumerable
s都是可重写的,根据提供
IEnumerable
的内容的实现情况,重新迭代那些可重写的可能会很昂贵。同样,考虑一个<代码> iQueabd返回随机数的情况——每次迭代它时,它会给出不同的值(假设种子每次都不一样)。 对50000个项目(5000次迭代)的排序列表进行的测试表明:

  • Lasse用了2137毫秒来确定它是否被分类
  • 我的方法用了2348毫秒来确定
    IEnumerable
    是否已排序
  • 矿工用了2403毫秒才返回结果

    • 这里有一个通用方法,应该检测序列是按递增顺序还是按递减顺序,然后检查集合的其余部分是否也按此顺序进行

      它还未经过全面测试,如果您决定使用它,您应该将数据集向左和向右抛出,并编写单元测试

      public static class CollectionExtensions
      {
          public static bool IsOrdered<T>(this IEnumerable<T> collection, IComparer<T> comparer = null)
          {
              comparer = comparer ?? Comparer<T>.Default;
      
              bool? expectedToIncrease = null;
              using (var enumerator = collection.GetEnumerator())
              {
                  bool gotFirst = enumerator.MoveNext();
                  if (!gotFirst)
                      return true; // empty collection is ordered
                  var first = enumerator.Current;
                  T second = default(T);
      
                  while (expectedToIncrease is null)
                  {
                      bool gotSecond = enumerator.MoveNext();
                      if (!gotSecond)
                          return true; // only equal elements are ordered
                      second = enumerator.Current;
      
                      switch (comparer.Compare(first, second))
                      {
                          case int i when i < 0:
                              expectedToIncrease = false;
                              break;
      
                          case int i when i > 0:
                              expectedToIncrease = true;
                              break;
                      }
      
                      if (expectedToIncrease is null)
                          first = second; // prepare for next round
                  }
      
                  while (enumerator.MoveNext())
                  {
                      if (expectedToIncrease.GetValueOrDefault())
                      {
                          if (comparer.Compare(second, enumerator.Current) < 0)
                              return false;
                      }
                      else
                      {
                          if (comparer.Compare(second, enumerator.Current) > 0)
                              return false;
                      }
                  }
      
                  return true;
              }
          }
      }
      
      公共静态类集合扩展
      {
      公共静态布尔已排序(此IEnumerable集合,IComparer comparer=null)
      {
      比较器=比较器??比较器。默认值;
      bool?expectedToIncrease=null;
      使用(var enumerator=collection.GetEnumerator())
      {
      bool gotFirst=enumerator.MoveNext();
      如果(!gotFirst)
      return true;//空集合已排序
      var first=枚举数。当前值;
      T秒=默认值(T);
      while(expectedToIncrease为空)
      {
      bool gotsond=枚举数.MoveNext();
      如果(!秒)
      return true;//只对相等的元素排序
      第二个=枚举数。当前;
      开关(比较器比较(第一,第二))
      {
      当i<0时的情况int i:
      expectedToIncrease=false;
      打破
      当i>0时的案例int i:
      expectedToIncrease=真;
      打破
      }
      如果(expectedToIncrease为空)
      first=second;//准备下一轮
      }
      while(枚举数.MoveNext())
      {
      如果(预期增加.GetValueOrDefault())
      {
      if(comparer.Compare(second,enumerator.Current)<0)
      返回false;
      }
      其他的
      {
      if(comparer.Compare(second,enumerator.Current)>0)
      返回false;
      }
      }
      返回true;
      }
      }
      }
      
      我提供了以下解决方案,它与其他解决方案的不同之处在于,您可以指定一个比较器,它将告诉您集合的排序顺序

      public static class LinqHelpers
      {
          [Flags]
          public enum SortDirections
          {
              NotSorted = 0,
              Ascending = 1,
              Descending = 2,
          }
          public static SortDirections GetSortDirection<T>(this IEnumerable<T> input, IComparer<T> comparer = null)
          {
              comparer = comparer ?? Comparer<T>.Default;
      
              bool isAsc = true;
              bool isDsc = true;
              bool isFirst = true;
              T last = default(T);
              foreach (var val in input)
              {
                  if (isFirst)
                  {
                      isFirst = false;
                  }
                  else
                  {
                      int cmp = comparer.Compare(last, val);
                      if (cmp > 0) isAsc = false;
                      if (cmp < 0) isDsc = false;
                  }
                  if (!isAsc && !isDsc) break;
                  last = val;
              }
              int result = 0;
              if (isAsc) result |= (int)SortDirections.Ascending;
              if (isDsc) result |= (int)SortDirections.Descending;
              return (SortDirections)result;
          }
      }
      
      公共静态类LinqHelpers
      {
      [旗帜]
      公共枚举排序方向
      {
      NotSorted=0,
      升序=1,
      下降=2,
      }
      公共静态SortDirections GetSortDirection(此IEnumerable输入,IComparer comparer=null)
      {
      比较器=比较器??比较器。默认值;
      bool-isAsc=true;
      bool-isDsc=true;
      bool isFirst=true;
      T last=默认值(T);
      foreach(输入中的var val)
      {
      如果(isFirst)
      {
      isFirst=false;
      }
      其他的
      {
      int cmp=比较器。比较(最后一个,val);
      如果(cmp>0)isAsc=false;
      如果(cmp<0)isDsc=false;
      }
      如果(!isAsc&&!isDsc)中断;
      last=val;
      }
      int结果=0;
      如果(isAsc)结果|=(int)SortDirections.升序;
      如果(isDsc)结果|=(int)SortDirections.Descending;
      返回(SortDirections)结果;
      }
      }
      
      一些边缘情况:

      • 如果元素为0,则认为它在两个方向上都已排序
      • 如果为1个元素,则认为它在两个方向上都已排序
      • 如果所有元素都相同,则视为在两个方向上排序
      Wh