我有这个扩展方法来检查是否对任何类型的列表进行了排序
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);
}
但是对于大型列表,这需要时间。有没有更有效的方法来获得相同的结果?
答案 0 :(得分:5)
这是一种通用方法,应先检测序列是按升序还是降序,然后检查集合的其余部分是否也照应。
尚未经过全面测试,如果决定使用此数据集,则应左右扔数据集并编写单元测试。
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;
}
}
}
答案 1 :(得分:3)
类似的事情应该起作用:
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;
}
它会在跟踪每个项目的同时浏览每个项目,然后使用默认的比较器(就像.OrderBy()
一样)检查它们是否已排序。为了允许沿任一方向检查排序,我存储了第一个非零比较的结果,并将其用作检查点。
正如评论中已经指出的那样,并非所有IEnumerable
都是可重复进行的,并且根据提供IEnumerable
的实现,重新迭代那些可能是昂贵的。另外,考虑一个IEnumerable
返回随机数的情况-每次迭代时,它都会给出不同的值(假设每次的种子都不相同)。
对50,000个项目(5,000个迭代)的排序列表进行测试后发现:
IEnumerable
是否已排序。答案 2 :(得分:2)
我提供了以下解决方案,该解决方案与其他解决方案的不同之处仅在于您可以指定比较器,它会告诉您排序集合的顺序。
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;
}
}
一些边缘情况:
为什么您的大型数据集速度慢?您正在排序数据,即O(n log n)。这个问题只需要是O(n)。