用于验证列表是升序还是降序的Linq表达式

本文关键字:Linq 表达式 降序 升序 验证 列表 用于 | 更新日期: 2023-09-27 18:02:43

我有一个IEnumerable<DateTime>变量,我需要验证它是升序排序还是降序排序。

我可以使用for循环做到这一点,但是有一种方法可以使用LINQ表达式做到这一点吗?

用于验证列表是升序还是降序的Linq表达式

升序:

myEnumerable.Zip(myEnumerable.Skip(1), (curr, next) => curr <= next).All(x => x);

下行:

myEnumerable.Zip(myEnumerable.Skip(1), (curr, next) => curr >= next).All(x => x);

但是使用循环,LINQ不是万能的。

var orderedByAsc = input.OrderBy(d => d);
if (input.SequenceEqual(orderedByAsc))
{
    Console.WriteLine("Ordered by Asc");
    return;
}
var orderedByDsc = input.OrderByDescending(d => d);
if (input.SequenceEqual(orderedByDsc))
{
    Console.WriteLine("Ordered by Dsc");
    return;
}
Console.WriteLine("not sorted");

LINQ扩展。MoreLinq库的良好候选:

public static bool IsOrdered<T>(this IEnumerable<T> source, IComparer<T> comparer = null)
{
    return source.IsOrdered(OrderByDirection.Ascending, comparer);
}
public static bool IsOrdered<T>(this IEnumerable<T> source, OrderByDirection direction, IComparer<T> comparer = null)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }
    if (comparer == null)
    {
        comparer = Comparer<T>.Default;
    }
    int d = direction == OrderByDirection.Ascending ? 1 : -1;
    Func<T, T, int> compareFunc= (i1, i2) => d * comparer.Compare(i1, i2);
    return IsOrderedImpl(source, compareFunc);
}
public static bool IsOrdered<T>(this IEnumerable<T> source, Func<T, T, int> compareFunc)
{
    if (source == null)
    {
        throw new ArgumentNullException(nameof(source));
    }
    if (compareFunc == null)
    {
        throw new ArgumentNullException(nameof(compareFunc));
    }
    return IsOrderedImpl(source, compareFunc);
}
private static bool IsOrderedImpl<T>(this IEnumerable<T> source, Func<T, T, int> compareFunc)
{
    T prevItem = default(T);
    int i = 0;
    foreach (T item in source)
    {
        if (i == 0)
        {
            prevItem = item;
        }
        else
        {
            if (compareFunc(prevItem, item) > 0)
            {
                return false;
            }
            prevItem = item;
        }
        ++i;
    }
    return true;
}
[TestMethod]
public void TestIsOrdered01()
{
    Assert.IsTrue(Enumerable.Range(1, 10).IsOrdered());
    Assert.IsFalse(Enumerable.Range(1, 10).Reverse().IsOrdered());
    Assert.IsTrue(Enumerable.Range(1, 10).IsOrdered(OrderByDirection.Ascending));
    Assert.IsFalse(Enumerable.Range(1, 10).IsOrdered(OrderByDirection.Descending));
    Assert.IsFalse(Enumerable.Range(1, 10).Reverse().IsOrdered(OrderByDirection.Ascending));
    Assert.IsTrue(Enumerable.Range(1, 10).Reverse().IsOrdered(OrderByDirection.Descending));
}

如果你确定列表是有序的,那么你可以简单地比较列表的第一个和最后一个元素,看看它是升序还是降序。

这可能是过度设计,但希望是教育和一些使用尽管如此!

public enum SortedState
{
    NoValues,
    Undecided,
    Ascending,
    Descending,
    Mixture
};
public class AscOrDescHelper<T> where T : IComparable<T>
{
    SortedState state;
    T lastValue;
    bool uniqueValues;
    public AscOrDescHelper()
    {
        state = SortedState.NoValues;
        uniqueValues = true;    // tentative assumption
    }
    public AscOrDescHelper<T> ProcessNextValue(T next)
    {
        switch (state)
        {
            case SortedState.NoValues:
                state = SortedState.Undecided;
                break;
            case SortedState.Undecided:
            case SortedState.Ascending:
            case SortedState.Descending:
                int cmp = next.CompareTo(lastValue);
                switch (state)
                {
                    case SortedState.Undecided:
                        if (cmp > 0)
                        {
                            state = SortedState.Ascending;
                        }
                        else if (cmp < 0)
                        {
                            state = SortedState.Descending;
                        }
                        else
                        {
                            uniqueValues = false;
                        }
                        break;
                    case SortedState.Ascending:
                        if (cmp < 0)
                        {
                            state = SortedState.Mixture;
                        }
                        else if (cmp == 0)
                        {
                            // Not unique
                            uniqueValues = false;
                        }
                        break;
                    case SortedState.Descending:
                        if (cmp > 0)
                        {
                            state = SortedState.Mixture;
                        }
                        else if (cmp == 0)
                        {
                            // Not unique
                            uniqueValues = false;
                        }
                        break;
                }
                break;
        }
        lastValue = next;
        return this;
    }
    public SortedState State()
    {
        return state;
    }
    public bool? Unique()
    {
        return state == SortedState.Mixture ? (bool?)null : uniqueValues;
    }
    public override string ToString()
    {
        return string.Format(
            "{0} ({1})",
            State(),
            Unique().HasValue ? (Unique().Value ? "unique" : "not unique")
                : "unknown uniqueness");
    }
};
static void CheckIfSorted<T>(IEnumerable<T> values) where T : IComparable<T>
{
    Console.WriteLine(
        values.Aggregate(
            new AscOrDescHelper<T>(),
            (last, next) => last.ProcessNextValue(next)));
}
static void Main()
{
    CheckIfSorted(new string[]{ "amy", "kate", "sally" });
    CheckIfSorted(new int[]{ 7, 5, 5 });
    CheckIfSorted(new int[]{ 2, 3, 1 });
    // Gives:
    //   Ascending (unique)
    //   Descending (not unique)
    //   Mixture (unknown uniqueness)
}

我是c#初学者,所以欢迎建设性的建议;)