【问题标题】:C# List<> Sort by x then yC# List<> 按 x 然后 y 排序
【发布时间】:2010-09-22 06:52:39
【问题描述】:

类似于List<> OrderBy Alphabetical Order,我们想先按一个元素排序,然后再按另一个。我们想要实现的功能等价于

SELECT * from Table ORDER BY x, y  

我们有一个包含许多排序函数的类,并且按一个元素排序没有问题。
例如:

public class MyClass {
    public int x;
    public int y;
}  

List<MyClass> MyList;

public void SortList() {
    MyList.Sort( MySortingFunction );
}

我们在列表中有以下内容:

Unsorted     Sorted(x)     Desired
---------    ---------    ---------
ID   x  y    ID   x  y    ID   x  y
[0]  0  1    [2]  0  2    [0]  0  1
[1]  1  1    [0]  0  1    [2]  0  2
[2]  0  2    [1]  1  1    [1]  1  1
[3]  1  2    [3]  1  2    [3]  1  2

稳定排序更可取,但不是必需的。欢迎使用适用于 .Net 2.0 的解决方案。

【问题讨论】:

  • @Bolu 我已经明确删除了标签以使发布版本不可知,并更新了与之匹配的答案。如果您认为 4.0/2.0 不够突出,请考虑在问题中进行澄清编辑,而不是恢复标签。
  • 对不起@AlexeiLevenkov,没太注意,请随意回滚。
  • 好的。已还原更改。
  • 此问题已更新,涵盖了 .Net 的所有版本,从最初的 2.0 开始 - 包含针对不同框架和要求的多个替代答案 - 全部查看,看看哪一个更符合您的要求。

标签: c# .net sorting


【解决方案1】:

对于可以使用 LINQ OrderByThenBy(或 ThenByDescending,如果需要)的 .Net 版本:

using System.Linq;
....
List<SomeClass>() a;
List<SomeClass> b = a.OrderBy(x => x.x).ThenBy(x => x.y).ToList();

注意:对于 .Net 2.0(或者如果您不能使用 LINQ),请参阅 Hans Passant answer 这个问题。

【讨论】:

  • 来自 phoog 的另一个回答帖子:stackoverflow.com/questions/9285426/… 它以新顺序创建包含原始项目的另一个列表。这仅在您需要保留原始顺序以用于其他目的时才有用;这比原地排序更浪费内存
【解决方案2】:

请记住,如果您比较所有成员,则不需要稳定的排序。根据要求,2.0 解决方案可能如下所示:

 public void SortList() {
     MyList.Sort(delegate(MyClass a, MyClass b)
     {
         int xdiff = a.x.CompareTo(b.x);
         if (xdiff != 0) return xdiff;
         else return a.y.CompareTo(b.y);
     });
 }

请注意,这个 2.0 解决方案仍然优于流行的 3.5 Linq 解决方案,它执行就地排序并且没有 Linq 方法的 O(n) 存储要求。当然,除非您希望原始 List 对象保持不变。

【讨论】:

    【解决方案3】:

    诀窍是实现稳定的排序。我创建了一个可以包含您的测试数据的 Widget 类:

    public class Widget : IComparable
    {
        int x;
        int y;
        public int X
        {
            get { return x; }
            set { x = value; }
        }
    
        public int Y
        {
            get { return y; }
            set { y = value; }
        }
    
        public Widget(int argx, int argy)
        {
            x = argx;
            y = argy;
        }
    
        public int CompareTo(object obj)
        {
            int result = 1;
            if (obj != null && obj is Widget)
            {
                Widget w = obj as Widget;
                result = this.X.CompareTo(w.X);
            }
            return result;
        }
    
        static public int Compare(Widget x, Widget y)
        {
            int result = 1;
            if (x != null && y != null)                
            {                
                result = x.CompareTo(y);
            }
            return result;
        }
    }
    

    我实现了 IComparable,所以它可以通过 List.Sort() 进行不稳定排序。

    不过,我还实现了静态方法 Compare,它可以作为委托传递给搜索方法。

    我从C# 411借用了这个插入排序方法:

     public static void InsertionSort<T>(IList<T> list, Comparison<T> comparison)
            {           
                int count = list.Count;
                for (int j = 1; j < count; j++)
                {
                    T key = list[j];
    
                    int i = j - 1;
                    for (; i >= 0 && comparison(list[i], key) > 0; i--)
                    {
                        list[i + 1] = list[i];
                    }
                    list[i + 1] = key;
                }
        }
    

    你可以把它放在你在问题中提到的排序助手类中。

    现在,使用它:

        static void Main(string[] args)
        {
            List<Widget> widgets = new List<Widget>();
    
            widgets.Add(new Widget(0, 1));
            widgets.Add(new Widget(1, 1));
            widgets.Add(new Widget(0, 2));
            widgets.Add(new Widget(1, 2));
    
            InsertionSort<Widget>(widgets, Widget.Compare);
    
            foreach (Widget w in widgets)
            {
                Console.WriteLine(w.X + ":" + w.Y);
            }
        }
    

    它输出:

    0:1
    0:2
    1:1
    1:2
    Press any key to continue . . .
    

    这可能会通过一些匿名代表来清理,但我会留给你。

    编辑:NoBugz 展示了匿名方法的力量......所以,考虑我的更老派:P

    【讨论】:

      【解决方案4】:

      这可能对你有帮助, How to Sort C# Generic List

      【讨论】:

        【解决方案5】:

        我遇到了一个问题,即 OrderBy 和 ThenBy 没有给我想要的结果(或者我只是不知道如何正确使用它们)。

        我选择了一个类似这样的列表排序解决方案。

            var data = (from o in database.Orders Where o.ClientId.Equals(clientId) select new {
            OrderId = o.id,
            OrderDate = o.orderDate,
            OrderBoolean = (SomeClass.SomeFunction(o.orderBoolean) ? 1 : 0)
            });
        
            data.Sort((o1, o2) => (o2.OrderBoolean.CompareTo(o1.OrderBoolean) != 0
            o2.OrderBoolean.CompareTo(o1.OrderBoolean) : o1.OrderDate.Value.CompareTo(o2.OrderDate.Value)));
        

        【讨论】:

          猜你喜欢
          • 2011-08-22
          • 1970-01-01
          • 1970-01-01
          • 2021-08-04
          • 2011-02-17
          • 2014-10-19
          • 1970-01-01
          • 2012-08-08
          相关资源
          最近更新 更多