C # List Classificar por x e y

Similar ao List OrderBy Ordem Alfabética , queremos ordenar por um elemento, depois outro. queremos alcançar o equivalente funcional de

SELECT * from Table ORDER BY x, y 

Temos uma class que contém várias funções de sorting e não temos problemas de sorting por um elemento.
Por exemplo:

 public class MyClass { public int x; public int y; } List MyList; public void SortList() { MyList.Sort( MySortingFunction ); } 

E nós temos o seguinte na lista:

 Unsorted Sorted(x) Desired --------- --------- --------- ID xy ID xy ID xy [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 

A sorting estável seria preferível, mas não obrigatória. A solução que funciona para o .Net 2.0 é bem-vinda.

Tenha em mente que você não precisa de um tipo estável se comparar todos os membros. A solução 2.0, conforme solicitado, pode ser assim:

  public void SortList() { MyList.Sort(delegate(MyClass a, MyClass b) { int xdiff = axCompareTo(bx); if (xdiff != 0) return xdiff; else return ayCompareTo(by); }); } 

Observe que essa solução 2.0 ainda é preferível em relação à popular solução 3.5 Linq, que realiza uma sorting no local e não possui o requisito de armazenamento O (n) da abordagem Linq. A menos que você prefira que o object List original seja intocado, é claro.

Para versões do .Net, onde você pode usar o LINQ OrderBy e o ThenBy (ou ThenByDescending se necessário):

 using System.Linq; .... List() a; List b = a.OrderBy(x => xx).ThenBy(x => xy).ToList(); 

Nota: para .Net 2.0 (ou se você não pode usar o LINQ), veja a resposta de Hans Passant a esta pergunta.

Você precisa implementar a interface IComparer . Aqui está um bom post com código de exemplo.

O truque é implementar um tipo estável. Eu criei uma class Widget que pode conter seus dados de teste:

 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(wX); } return result; } static public int Compare(Widget x, Widget y) { int result = 1; if (x != null && y != null) { result = x.CompareTo(y); } return result; } } 

Eu implementei IComparable, para que ele possa ser ordenado instável por List.Sort ().

No entanto, também implementei o método estático Compare, que pode ser passado como um delegado para um método de pesquisa.

Eu peguei emprestado esse método de inserção de inserção do C # 411 :

  public static void InsertionSort(IList list, Comparison 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; } } 

Você colocaria isso na class dos auxiliares de sorting que você mencionou na sua pergunta.

Agora, para usá-lo:

  static void Main(string[] args) { List widgets = new List(); 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(widgets, Widget.Compare); foreach (Widget w in widgets) { Console.WriteLine(wX + ":" + wY); } } 

E isso gera:

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

Isso provavelmente poderia ser limpo com alguns delegates anônimos, mas vou deixar isso para você.

EDIT : E NoBugz demonstra o poder dos methods anônimos … então, considere o meu mais oldschool: P

Isso pode ajudá-lo, Como Classificar Lista Genérica C #

Eu tive um problema em que OrderBy e ThenBy não me deram o resultado desejado (ou eu simplesmente não sabia como usá-los corretamente).

Eu fui com uma solução list.Sort algo parecido com isto.

  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)));