C # 목록 <> x, y 순으로 정렬


88

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이 충분히 눈에 띄지 않는다고 생각되면 태그를 복원하는 대신 질문에서 명확한 편집을 고려하십시오.
Alexei Levenkov 2014 년

죄송합니다 @AlexeiLevenkov, 많은 관심을 기울이지 않았으므로 언제든지 롤백하십시오.
Bolu

확인. 변경 사항을 되돌 렸습니다.
Alexei Levenkov 2014 년

이 질문은 원래 2.0에서 .Net의 모든 버전을 포함하도록 업데이트되었습니다. 다른 프레임 워크와 요구 사항에 대한 몇 가지 대체 답변이 포함되어 있습니다. 모두 확인하여 요구 사항에 더 적합한 것이 무엇인지 확인하십시오.
Alexei Levenkov 2014 년

답변:


98

모든 멤버를 비교하는 경우 안정적인 정렬이 필요하지 않습니다. 요청에 따라 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 개체를 변경하지 않는 것이 좋습니다.


156

당신이 LINQ 사용할 수있는 닷넷의 버전 OrderByThenBy(또는 ThenByDescending필요한 경우) :

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 답변 을 참조 하세요.


2
여기 phoog의 다른 답변 게시물에서 : stackoverflow.com/questions/9285426/… 새 순서로 원래 항목으로 또 다른 목록을 만듭니다. 이것은 다른 목적을 위해 원래 순서를 유지해야하는 경우에만 유용합니다. 목록을 제자리에 정렬하는 것보다 메모리 낭비가 더
많습니다


5

트릭은 안정적인 정렬을 구현하는 것입니다. 테스트 데이터를 포함 할 수있는 위젯 클래스를 만들었습니다.

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



1

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)));
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.