【问题标题】:C# sorting arrays in ascending and descending orderC#按升序和降序对数组进行排序
【发布时间】:2015-08-30 21:27:17
【问题描述】:

我在编写一个方法时遇到问题,如果数组(数字)的元素按升序或降序排序,则返回 true;如果它们未按任何排序顺序,则返回 false。如果数组是升序的,我可以返回正确的布尔值,但我不知道如何以相同的方法检查降序。我目前有:

public static bool IsArraySorted(int[] numbers)
{
    for (int i = 1; i < numbers.Length; i++)
    {
        if (numbers[i - 1] > numbers[i])
            return false;
    }

    return true;
}

谁能提供有关如何检查排序降序数组的帮助?干杯!

【问题讨论】:

  • 如果有两个连续值具有相同的数字,这是期望的行为?
  • 使用 return 退出你的函数,而你大概想在返回任何东西之前循环整个集合......
  • @Bartdude 我认为这是设计使然 - 如果您已经发现它没有排序,则无需检查数组的其余部分 :-)

标签: c# arrays sorting


【解决方案1】:
public static boolean checkSortedness(final int[] data) 
{
    for (int i = 1; i < data.length; i++) 
    {
        if (data[i-1] > data[i]) {
            return false;
        }
    }
    return true;
}

【讨论】:

  • 这仅验证升序排序列表,但在降序排序列表中失败
  • final 是 Java,而不是 C#
【解决方案2】:

应该是这样的:

public static bool IsArraySorted(int[] numbers)
{
    bool? ascending = null;

    for (int i = 1; i < numbers.Length; i++)
    {
        if (numbers[i - 1] != numbers[i])
        {
            bool ascending2 = numbers[i - 1] < numbers[i];

            if (ascending == null)
            {
                ascending = ascending2;
            }
            else if (ascending.Value != ascending2)
            {
                return false;
            }
        }
    }

    return true;
}

注意使用ascending 变量来保存数组的“方向”。它在第一次找到两个不同的元素时被初始化。

注意,如果你愿意,你甚至可以返回数组的“方向”:

public static bool IsArraySorted(int[] numbers, out bool isAscending)
{
    isAscending = true;
    bool? ascending = null;

if (ascending == null)里面

if (ascending == null)
{
    ascending = ascending2;
    isAscending = ascending2;
}

这是基于IEnumerable&lt;TSource&gt;的通用版本:

public static bool IsSorted<TSource>(IEnumerable<TSource> source, out bool isAscending, Comparer<TSource> comparer = null)
{
    isAscending = true;

    if (comparer == null)
    {
        comparer = Comparer<TSource>.Default;
    }

    bool first = true;
    TSource previous = default(TSource);

    bool? ascending = null;

    foreach (TSource current in source)
    {
        if (!first)
        {
            int cmp = comparer.Compare(previous, current);

            if (cmp != 0)
            {
                bool ascending2 = cmp < 0;

                if (ascending == null)
                {
                    ascending = ascending2;
                    isAscending = ascending2;
                }
                else if (ascending.Value != ascending2)
                {
                    return false;
                }
            }
        }

        first = false;
        previous = current;
    }

    return true;
}

注意使用bool first/TSource previous 来处理i - 1(事实上for 循环能够“跳过”第一个元素)

【讨论】:

  • 我只能使用 (numbers.Length/2) insted 来遍历完整列表吗?
  • @Amit ???? { 1, 2, 3, -5 } 如果不检查最后一个值,您将如何捕获乱序的-5
  • @xanatos,如果传入的数组长度为 0 或 1,您将获得 OutOfRangeException。您需要在方法顶部进行一些参数检查。
  • @WyattEarp 否...因为在for () 之前没有代码访问数组,而for() 将阻塞length &lt;= 1int i = 1; i &lt; numbers.Length 的数组
  • @xanatos,啊,我的错。不过,如果数组为空,您会得到 NullReferenceException
【解决方案3】:

使用 Linq -

public static bool IsArraySorted(int[] numbers)
{
    var orderedAsc = numbers.OrderBy(a => a);
    var orderedDes = numbers.OrderByDescending(a => a);

    bool isSorted = numbers.SequenceEqual(orderedAsc) ||
                    numbers.SequenceEqual(orderedDes);
    return isSorted;
}

【讨论】:

    【解决方案4】:

    这使用一个循环来测试两种情况:

    public static bool IsSorted<T>(IEnumerable<T> items, Comparer<T> comparer = null)
    {
        if (items == null) throw new ArgumentNullException("items");
        if (!items.Skip(1).Any()) return true;  // only one item
    
        if (comparer == null) comparer = Comparer<T>.Default;
        bool ascendingOrder = true; bool descendingOrder = true;
    
        T last = items.First();
        foreach (T current in items.Skip(1))
        {
            int diff = comparer.Compare(last, current);
            if (diff > 0)
            {
                ascendingOrder = false;
            }
            if (diff < 0)
            {
                descendingOrder = false;
            }
            last = current;
            if(!ascendingOrder && !descendingOrder) return false;
        }
        return (ascendingOrder || descendingOrder);
    }
    

    用法:

    int[] ints = { 1, 2, 3, 4, 5, 6 };
    bool isOrderedAsc = IsSorted(ints); // true
    bool isOrderedDesc = IsSorted(ints.Reverse()); //true
    

    如果你把它作为扩展方法,你可以将它用于任何类型:

    bool ordered = new[]{"A", "B", "C"}.IsSorted();
    

    【讨论】:

    • 我确实认为将IEnumerable&lt;&gt; 枚举两次是可憎的 非常糟糕的坏事... (First/@ 987654326@)
    • @xanatos:为什么?我不会枚举两次。如果它是一个集合,它只是获取第一项,而 Skip(1) 是省略第一项的枚举。什么是可憎的?
    • 尝试对IQueryable&lt;&gt;执行此操作... 查询被解析两次(从技术上讲,执行了两个不同的查询...一个具有TOP 1,另一个模拟Skip(1)
    • @xanatos:为什么要使用这种方法进行数据库查询?你可以,但这不是为了这个目的。另一方面,您的方法根本不可重用。他可以将签名更改为仅接受IList&lt;T&gt;,但我不会。
    • 您的代码/解释中是否有明确表示“我将枚举两次,如果您使用慢速IEnumerable&lt;&gt;,请不要使用我”?警告贴纸很重要。
    【解决方案5】:

    我的答案在哪里?我大约一个小时前写的:

    public enum SortType
    {
         unsorted   = 0,
         ascending  = 1,
         descending = 2
    }
    
    public static SortType IsArraySorted(int[] numbers)
    {
        bool ascSorted = true;
        bool descSorted = true;
    
        List<int> asc = new List<int>(numbers);            
    
        asc.Sort();
    
        for (int i = 0; i < asc.Count; i++)
        {
            if (numbers[i] != asc[i]) ascSorted = false;
            if (numbers[asc.Count - 1 - i] != asc[i]) descSorted = false;
        }
    
        return ascSorted ? SortType.ascending : (descSorted? SortType.descending : SortType.unsorted);
    }
    

    例子:

    【讨论】:

      【解决方案6】:

      这看起来更像是一项学术作业,而不是一个实际问题。我想偶尔回归基础并没有什么坏处:

      public static bool IsSortedAscOrDesc(int[] arr)
      {
          int last = arr.Length - 1;
          if (last < 1) return true;
      
          bool isSortedAsc = true;
          bool isSortedDesc = true;
      
          int i = 0;
          while (i < last && (isSortedAsc || isSortedDesc)) 
          {
              isSortedAsc &= (arr[i] <= arr[i + 1]);
              isSortedDesc &= (arr[i] >= arr[i + 1]);
              i++;
          }
      
          return isSortedAsc || isSortedDesc;
      }
      

      【讨论】:

        【解决方案7】:

        对具有 2 个(或更少)元素的数组进行排序,
        {0,0} 按 asc & desc 排序,{0,1} asc, {1,0} desc, {1,1} asc & desc.
        可以使用一个循环,但分离案例似乎更快。 对于超过 2 个元素的数组,
        如果第一个元素小于最后一个元素, 检查:a[i] 下面我使用“ai

        using System;
        class Program
        {
            static void Main()
            {
                int i = 512; int[] a = new int[i--]; while (i > 0) a[i] = i--; //a[511] = 1;
                Console.WriteLine(isSorted0(a));
                var w = System.Diagnostics.Stopwatch.StartNew();
                for (i = 1000000; i > 0; i--) isSorted0(a);
                Console.Write(w.ElapsedMilliseconds); Console.Read();
            }
        
            static bool isSorted0(int[] a)  // 267 ms
            {
                if (a.Length < 3) return true; int j = a.Length - 1;
                return a[0] < a[j] ? incr(a) : a[0] > a[j] ? decr(a) : same(a);
            }
            static bool incr(int[] a)
            {
                int ai = a[0], i = 1, j = a.Length;
                while (i < j && ai <= (ai = a[i])) i++; return i == j;
            }
            static bool decr(int[] a)
            {
                int ai = a[0], i = 1, j = a.Length;
                while (i < j && ai >= (ai = a[i])) i++; return i == j;
            }
            static bool same(int[] a)
            {
                int ai = a[0], i = 1, j = a.Length - 1;
                while (i < j && ai == a[i]) i++; return i == j;
            }
        
            static bool isSorted1(int[] numbers)  // 912 ms  accepted answer
            {
                bool? ascending = null;
                for (int i = 1; i < numbers.Length; i++)
                    if (numbers[i - 1] != numbers[i])
                    {
                        bool ascending2 = numbers[i - 1] < numbers[i];
                        if (ascending == null) ascending = ascending2;
                        else if (ascending.Value != ascending2) return false;
                    }
                return true;
            }
        }
        

        一个简短的版本。

            static bool isSorted(int[] a)
            {
                if (a.Length < 3) return true; int i = a.Length - 1, ai = a[i--];
                if (ai > a[0]) while (i >= 0 && ai >= (ai = a[i])) i--;
                else if (ai < a[0]) while (i >= 0 && ai <= (ai = a[i])) i--;
                else while (i >= 0 && ai == a[i]) i--; return i < 0;
            }
        

        【讨论】:

          猜你喜欢
          • 2016-10-18
          • 1970-01-01
          • 1970-01-01
          • 2020-11-09
          • 1970-01-01
          • 2020-06-06
          • 2014-02-16
          • 2022-12-13
          相关资源
          最近更新 更多