Sortuj listę alfabetycznie

83

Mam następującą klasę:

class Detail
{
    public Detail()
    {
        _details = new List<string>();
    }
    public IList<string> Details { get { return _details; } }
    private readonly List<string> _details;
}

Obecnie sortuję klasę losowo, korzystając z:

void ShuffleGenericList<T>(IList<T> list)
{
    //generate a Random instance
    var rnd = new Random();
    //get the count of items in the list
    var i = list.Count();
    //do we have a reference type or a value type
    T val = default(T);

    //we will loop through the list backwards
    while (i >= 1)
    {
        //decrement our counter
        i--;
        //grab the next random item from the list
        var nextIndex = rnd.Next(i, list.Count());
        val = list[nextIndex];
        //start swapping values
        list[nextIndex] = list[i];
        list[i] = val;
    }
}

Chciałbym uporządkować zawartość szczegółów w porządku alfabetycznym.

Na przykład, jeśli zawartość wygląda tak:

[0] a
[1] d
[2] b

Chcę móc uruchomić tę metodę i posortować je w:

[0] a
[1] b
[2] d

Czy ktoś zna prosty sposób na zrobienie tego? Zauważ, że listy zwykle zawierają mniej niż dziesięć wpisów. Czy mogę to zrobić z LINQ? Przepraszam, ale nie znam LINQ. Właśnie usłyszałem sugestię, że mógłbym go użyć.

Mariko
źródło

Odpowiedzi:

155

Można sortować listę w miejscu po prostu przez wywołanie List<T>.Sort:

list.Sort();

Spowoduje to wykorzystanie naturalnego uporządkowania elementów, co w Twoim przypadku jest w porządku.

EDYCJA: Zwróć uwagę, że w swoim kodzie potrzebujesz

_details.Sort();

ponieważ Sortmetoda jest zdefiniowana tylko w List<T>, nie IList<T>. Jeśli chcesz posortować go z zewnątrz, gdzie nie masz do niego dostępu List<T>(nie powinieneś go rzucać, ponieważ List<T>część jest szczegółem implementacji), musisz wykonać trochę więcej pracy.

Nie znam żadnych IList<T>lokalnych rodzajów sortowania w .NET, co jest nieco dziwne, gdy o tym pomyślę. IList<T>zapewnia wszystko, czego potrzebujesz, więc może go zapisać jako metodę rozszerzającą. Istnieje wiele implementacji quicksort, jeśli chcesz użyć jednej z nich.

Jeśli nie zależy Ci na odrobinie nieefektywności, zawsze możesz użyć:

public void Sort<T>(IList<T> list)
{
    List<T> tmp = new List<T>(list);
    tmp.Sort();
    for (int i = 0; i < tmp.Count; i++)
    {
        list[i] = tmp[i];
    }
}

Innymi słowy, skopiuj, posortuj w miejscu, a następnie skopiuj posortowaną listę z powrotem.


Możesz użyć LINQ, aby utworzyć nową listę, która zawiera oryginalne wartości, ale posortowane:

var sortedList = list.OrderBy(x => x).ToList();

To zależy od tego, jakiego zachowania chcesz. Pamiętaj, że Twoja metoda odtwarzania losowego nie jest idealna:

  • Tworzenie nowego Randomw metodzie napotyka na niektóre z przedstawionych tutaj problemów
  • Możesz zadeklarować valwewnątrz pętli - nie używasz tej wartości domyślnej
  • Korzystanie z tej Countwłaściwości jest bardziej idiomatyczne, gdy wiesz, że pracujesz z plikiemIList<T>
  • Moim zdaniem forpętla jest prostsza do zrozumienia niż przechodzenie przez listę wstecz za pomocą whilepętli

Istnieją inne implementacje tasowania z Fisherem-Yatesem na przepełnieniu stosu - wyszukaj, a znajdziesz je dość szybko.

Jon Skeet
źródło
Więc gdybym chciał posortować listę, którą utworzyłeś powyżej, musiałbym po prostu powiedzieć: sortList.Sort?
Mariko
Próbowałem sortowania, ale nie mogę go uruchomić. - Moja lista wygląda następująco: IList <string> nD. Próbowałem nD.Sort (), ale wyświetla się komunikat: Nie można rozpoznać symbolu „Sortuj”.
Mariko
@Mariko: Użyj _details.Sort()zamiast tego - tak jak _detailsjest zadeklarowane jako List<string>zamiast IList<string>. Sortjest tylko deklarowane List<T>, a nie IList<T>.
Jon Skeet
25

Istnieją dwa sposoby:

Bez LINQ: yourList.Sort();

Z LINQ: yourList.OrderBy(x => x).ToList()

Więcej informacji znajdziesz na: https://www.dotnetperls.com/sort

Damiox
źródło
@Dminox - Moja lista wygląda następująco: IList <string> nD. Próbowałem nD.Sort (), ale wyświetla się komunikat: Nie można rozpoznać symbolu „Sortuj”.
Mariko,
1
@Mariko Sort()jest członkiem List<T> not IList<T> . Możesz rozważyć przejście na tę pierwszą (chyba że spodziewasz się pracy z różnymi IList<T>implementacjami).
dlev
24

Inny sposób

_details.Sort((s1, s2) => s1.CompareTo(s2)); 
lahsrah
źródło
10
Ten ma tę zaletę, że dostosowuje się do sortowania dowolnego obiektu według jednej z jego właściwości .
MGOwen
11

Powinieneś móc używać OrderByw LINQ ...

var sortedItems = myList.OrderBy(s => s);
Quintin Robinson
źródło
2
Uwaga: to zwraca IEnumerable<T>i nie jest sortowane na miejscu
abatishchev
1

Co jest nie tak List<T>.Sort()?

https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort#overloads

Oleg Dudnyk
źródło
@goril - chciałbym tego użyć, ale pojawia się błąd. To właśnie dodałem do drugiego komentarza. Mam nadzieję, że możesz pomóc - Moja lista wygląda następująco: IList <string> nD. Próbowałem nD.Sort (), ale wyświetla się komunikat: Nie można rozpoznać symbolu „Sortuj”.
Mariko,
1
@Mariko: używasz interfejsu IList <T>, który nie zawiera metody Sort. Sortuj zmienną List <T> bezpośrednio. Innymi słowy, możesz sortować na _detailspodstawie swojego przykładu, ale nieDetails
Oleg Dudnyk