2009-07-20 15 views
10

Byłem bardzo zaskoczony, gdy odkryłem, że nie ma bezpośredniego sposobu sortowania lub wykonywania wyszukiwania binarnego na IList < T>. Tak jak istnieją statyczne metody do sortowania i przeprowadzania wyszukiwania binarnego na tablicy, myślę, że byłoby bardzo pomocne mieć podobne statyczne metody, które wymagają IList < T>.Dlaczego nie ma Sortuj dla IList <T>?!?! (edytowane)

Aktualnie

class Array 
{ 
    static Sort<T>(T[] array); 
    static int BinarySearch<T>(T[] array, T item); 
} 

życzę oni by dodać:

class List 
{ 
    static Sort<T>(IList<T> list); 
    static int BinarySearch<T>(IList<T> list, T item); 
} 

Zerknęłam na .NET Framework 4.0 Beta SDK i tam nadal nie wydaje się być rozwiązaniem ten problem.

Wiem, że mógłbym obejść ten problem, tworząc metodę rozszerzenia, która sprawdza, czy jest to lista < T>, a następnie sortuj/wyszukuj używając instancji List < T>; Jeśli jednak nie jest to instancją Listy < T>, to muszę wykonać kopię (która śmierdzi na bardzo duże listy). Wiem, że mogłem to wszystko zrobić, ale dlaczego? Czy jest jakiś powód, dla którego celowo pominęli tę funkcję?

Aby spróbować uzyskać to w środowisku .NET 4.0 Framework, stworzyłem sugestię za pośrednictwem programu Connect firmy Microsoft. Jeśli jesteś sfrustrowany, tak jak ja, w tej sprawie, zagłosuj na niego, a może zostanie dodany.

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=474201

+0

Czy możesz zmienić to jako pytanie, być może "Czy istnieje powód, dla którego C# nie ma wbudowanego sortowania i wyszukiwania binarnego dla IList ?" W tej chwili wydajesz tylko oświadczenie i wzywanie ludzi do głosowania na to na stronie internetowej Microsoftu, co grozi zamknięciem jako spam. – Kip

+0

Jest to rodzaj ukrytego w chaosie, ale jest tam pytanie, które może pomóc Rozumiem, dlaczego go nie ma, jeśli Microsoft celowo go pominął: "Czy jest jakiś powód, dla którego celowo pominęli tę funkcję?" – dewald

+0

Przepełnienie stosu jest stroną z pytaniami/odpowiedziami. na etykiecie należy zwrócić większą uwagę na swoje pytanie (zwłaszcza w tytule pytania). teraz brzmi, jakbyś już założył, że to błąd i chcesz, żeby inni mówili Microsoftowi, że się zgadzasz. lepszym duchem SO byłoby wyjaśnienie, że pytanie brzmi "czy istnieje ku temu dobry powód, czy jest to błąd?" – Kip

Odpowiedz

17

LINQ ma metodę OrderBy, która działa na wszystkich IEnumerable <T>, w tym IList <T>. Możesz zrobić to samo, używając OrderBy.

// Order a list of addresses: 
IList<string> list = ... 
var orderedList = list.OrderBy(input => input); 
+0

Czy wiesz, jak robią to pod kołdrą? Zakładam, że ponieważ moduły wyliczające są zwykle oceniane tylko wtedy, gdy są potrzebne (ocena leniwy), wówczas zostanie użyty rodzaj sortowania, który byłby śmierdzący, ponieważ jest to O (n^2). – dewald

+3

@dewald - Myślę, że ogólną zasadą jest, że operatorzy LINQ-to-Object są "tak leniwi, jak to jest odpowiednie dla większości zastosowań". Biorąc pod uwagę, że niektóre implementacje IEnumerable mogą być leniwy, posiadanie OrderBy wielokrotnie wyliczanych przez dane wejściowe w poszukiwaniu kolejno niższych wartości byłoby bardzo nieekonomiczne. Powiedział, że jeśli dobrze czytam, używa EnumerableSorter .QuickSort pod okładkami, tj. implementacja QuickSort na podstawie tablicy. –

+2

Jeśli obawiasz się, czy sortowanie jest natychmiastowe czy leniwy, to zamiast listy.OrderBy (...), użyj list.OrderBy (...). ToList(), które wymusi sortowanie natychmiast . –

2

Trzeba ArrayList.Adapter, który umożliwia korzystanie z ArrayList „s sortujących rutyny, ale spowodowałoby to ogromny wpływ na wydajność dla ogólnych listach typów wartości odpakowanych, plus zarówno wirtualnych połączeń i interfejs wysyłki napowietrznych.

Dla obu typów referencyjnych i wartości, wysyłka interfejs może być kosztowne, czyli wezwanie do ICollection<T>.CopyTo tablicę T[] następnie oddzielnego rodzaju mogłaby być opcja najszybszy ogólnego przeznaczenia, w tym rozszerzenie niestandardowego bezpośrednio porządek na obiekcie IList<T>.

List<T> ma metodę Sort ponieważ może bardzo skutecznie działać na bazowym tablicy typu T[]. Po prostu nie można tego zrobić dla arbitralnego IList<T>.

+0

Na podstawie postu Hallgrima na http://stackoverflow.com/questions/226981/what-is-the-best-way-to-sort-an-ilistt-in-net-2-0, wydaje się, że za pomocą ArrayList. Adapter (IList) z IList < T > wykona niepotrzebne kopiowanie, którego próbuję uniknąć. – dewald

10

Myślę, że jest całkiem niezły przypadek, ponieważ nie uwzględniono metody sortowania dla IList<T>. Po pierwsze, spowodowałoby to dodatkową złożoność dla tych, którzy chcą wdrożyć IList, a po drugie utrudniłoby interfejs IList dostosowanie się do Interface Segregation Principle.

Ogólnie co zrobić, jeśli trzeba wykonać coś w rodzaju na IList<T> jest utworzyć nową List<T> i przechodzą w IList<T> jako parametr

tak na przykład:

 public IList<Address> SortAddresses(IList<Address> addresses) 
     { 
      var sortedAddresses = new List<Address>(addresses); 
      sortedAddresses.Sort(); 
      return sortedAddresses; 
     } 
+1

Należy jednak pamiętać, że nie spowoduje to uporządkowania listy (co może nie być problemem). –

+0

dla mnie, nie, ale zgadzam się, to ważna kwestia. – lomaxx

+2

@lomaxx: Jak mogłoby to zwiększyć złożoność tych klas, które implementują IList <>? Właściwości get/set już istnieją, a te mogą być po prostu użyte w statycznej metodzie sortowania (lista ). – dewald

0

nie jestem ekspert C#, ale bardzo niewiele implementacji list obsługuje sortowanie, wyszukiwanie binarne, a nawet indeksowane pobieranie. Listy są zwykle oparte na linked lists, które zazwyczaj nie oferują sposobu pobrania elementu według jego indeksu.Jeśli chcesz szybko znaleźć element, użyj czegoś, co spowoduje uporządkowanie elementów, takich jak tree lub tablica, jak sugerują inni.

Znalazłem fakt, że IList zawiera interesującą indexed retrieval method. Możesz rozważyć użycie SortedList zamiast List, ponieważ wygląda na to, że powinno obsługiwać wyszukiwania według indeksu lub klucza w czasie O(1). Ogólnie rzecz biorąc, jeśli potrzebujesz czegoś, co zapewnia szybkie wyszukiwanie, poszukaj struktury danych, która zachowa swoje elementy, zamiast ich wyraźnego sortowania. Jeśli nic więcej, C# ma już litanię struktur danych.

+1

W języku C# "lista" zazwyczaj zapewnia bezpośrednie indeksowanie elementów na górze "kolekcji", która jest po prostu dodawaniem/usuwaniem elementów. –

+1

Możesz sortować połączone listy w O (nlgn) z sortowaniem scalonym. –

+1

Nie jestem faktycznie świadomy jakiejkolwiek implementacji 'IList ', która używa listy połączonej jako pamięci masowej. W szczególności klasa 'LinkedList ' nie _ implementuje 'IList '. –

4

Dobrą wiadomością jest to, że można napisać takie metody dość łatwo; a dzięki C# 3.0 metod rozszerzenie, można dokonać tej pracy na interfejsie:

public static class ListExt 
{ 
    public static void AddRange<T>(this IList<T> list, IEnumerable<T> items) { 
     foreach(T item in items) list.Add(item); 
    } 
    public static void Sort<T>(this IList<T> list) { 
     Sort<T>(list,Comparer<T>.Default); // ordinal sort by default 
    } 
    public static void Sort<T>(this IList<T> list, IComparer<T> comparer) 
    { // very poor implementation! 
     List<T> concreteList = new List<T>(list); 
     concreteList.Sort(comparer); // cheat! 
     list.Clear(); 
     list.AddRange(concreteList); 
    } 
    public static int BinarySearch<T>(this IList<T> list, T item) { 
     return BinarySearch<T>(list, item, Comparer<T>.Default); 
    } 
    public static int BinarySearch<T>(this IList<T> list, T item, 
     IComparer<T> comparer) 
    {...} // TODO 
} 

Teraz pozostaje tylko sam kod TODO (i probaby ponownie napisać Sort ;-p); ale po tym:

IList<T> list = ... 
list.Sort(); 
T huntFor = ... 
int i = list.BinarySearch(huntFor); 

ważne, IList<T> ma odczytu/zapisu podziałowe, więc na pewno jest to możliwe do zrobienia zarówno rodzaj i binarne-wyszukiwanie bez hack powyżej.

+0

@Marc: To są ładne metody rozszerzenia, jednak jestem tylko zaskoczony, że musimy napisać kod, aby wykonać te podstawowe operacje. Tak jak powiedziałeś, "IList ma indeksowanie odczytu/zapisu, więc z pewnością można wykonać sortowanie i wyszukiwanie binarne bez użycia hacka powyżej". Moim zdaniem te metody powinny stanowić część ram, aby uniemożliwić każdemu projektowi stworzenie własnej wersji. – dewald

Powiązane problemy