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个元素,则认为它在两个方向上都已排序李>
- 如果所有元素都相同,则视为在两个方向上排序