2009-07-20 6 views
10

Sono rimasto piuttosto sorpreso quando ho scoperto che non esiste un modo diretto per ordinare o eseguire una ricerca binaria su un IList < T>. Proprio come ci sono metodi statici per ordinare ed eseguire una ricerca binaria su una matrice, penso che sarebbe terribilmente utile avere metodi statici simili che richiedono un IList < T>.Perché non esiste un ordinamento per IList <T>?!?! (modificato)

Attualmente:

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

Vorrei che si aggiungere:

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

Diedi un'occhiata al .NET Framework 4.0 Beta SDK e ci ancora non sembra essere una soluzione per questo problema.

So che potrei aggirare questo creando un metodo di estensione che controlla se si tratta di un elenco < T> e quindi ordinare/cercare utilizzando l'istanza Elenco < T>; tuttavia, se non è un'istanza di un elenco < T>, quindi devo eseguire una copia (che puzza per elenchi molto grandi). So che potrei fare tutto questo, ma perché? C'è qualche ragione per cui hanno intenzionalmente omesso questa funzione?

Per provare a ottenere questo nel .NET Framework 4.0, ho creato un suggerimento tramite il programma Connect di Microsoft. Se sei frustrato come me riguardo a questo problema, votalo e forse verrà aggiunto.

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

+0

puoi riformulare questo come una domanda, forse "C'è qualche ragione in cui C# non ha ordinamento e ricerca binaria incorporati per IList ?" in questo momento stai solo facendo una dichiarazione e invitando le persone a votare per questo sul sito di microsoft, che rischia di essere chiuso come spam – Kip

+0

È un po 'nascosto nel vagabondaggio, ma c'è una domanda in là per aiutare capisco perché non è lì se Microsoft l'ha intenzionalmente lasciato fuori: "C'è qualche ragione per cui hanno intenzionalmente omesso questa funzione?" – dewald

+0

overflow dello stack di pozzetti è un sito di domande/risposte. è buona norma mettere più attenzione alla tua domanda (specialmente nel titolo della domanda). in questo momento sembra che tu abbia già dato per scontato che si tratti di un bug e vuoi che gli altri dica a Microsoft che sei d'accordo. migliore spirito di SO sarebbe quello di chiarire che la domanda è "c'è una buona ragione per questo o è un bug?" – Kip

risposta

17

LINQ ha un metodo OrderBy che funziona su tutti IEnumerable <T>, incluso IList <T>. Puoi realizzare la stessa cosa usando OrderBy.

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

Sai come lo fanno sotto le coperte? Suppongo che, poiché gli enumeratori vengono di solito valutati solo quando sono necessari (valutazione lazy), allora verrà usato qualcosa come un ordinamento di selezione che puzzerebbe dato che è O (n^2). – dewald

+3

@dewald - Penso che la regola generale sia che gli operatori LINQ-to-Objects sono "pigri quanto è appropriato per la maggior parte degli usi". Date alcune implementazioni IEnumerable può essere pigro, avere OrderBy ripetutamente enumerare attraverso l'input alla ricerca di valori successivamente inferiori sarebbe estremamente dispendioso. Detto questo, se sto leggendo le cose, usa EnumerableSorter . QuickSort sotto le copertine, es. un'implementazione QuickSort basata su array. –

+2

Se si è preoccupati che l'ordinamento sia immediato o pigro, invece di list.OrderBy (...), utilizzare list.OrderBy (...). ToList(), che imporrà l'ordinamento immediatamente. . –

2

Tu devi ArrayList.Adapter che consente l'utilizzo di ArrayList 's ordinamento routine, ma causerebbe un enorme impatto sulle prestazioni per le liste generiche di tipi di valore unboxed, più sia chiamata e l'invio di interfaccia in testa virtuale.

Per entrambi i tipi di riferimento e il valore, l'invio interfaccia potrebbe essere costoso, cioè una chiamata a ICollection<T>.CopyTo un array T[] seguito da liste separato potrebbe essere l'opzione scopo veloce generale, compreso un'estensione personalizzata per direttamente ordinamento sull'oggetto IList<T>.

List<T> ha un metodo Sort perché può molto operare efficientemente sulla matrice sottostante di tipo T[]. Semplicemente non c'è modo di farlo per un arbitrario IList<T>.

+0

Sulla base del post di Hallgrim su http://stackoverflow.com/questions/226981/what-is-the-best-way-to-sort-an-ilistt-in-net-2-0, sembra che l'utilizzo di ArrayList. Adattatore (IList) con un IList < T > eseguirà una copia non necessaria che sto cercando di evitare. – dewald

10

Penso che ci sia un buon caso per non includere un metodo di ordinamento per IList<T>. Innanzitutto, creerebbe una complessità aggiuntiva per coloro che desiderano implementare un IList e in secondo luogo renderebbe più difficile per l'interfaccia IList essere conforme allo Interface Segregation Principle.

In generale quello che faccio se ho bisogno di eseguire una sorta su un IList<T> è creare un nuovo List<T> e passare nel IList<T> come parametro

così per esempio:

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

Tuttavia, è importante rendersi conto che questo non ordinerà l'elenco in posizione (che potrebbe non essere un problema). –

+0

per me, no, ma sono d'accordo, è un punto importante. – lomaxx

+2

@lomaxx: come creerebbe una maggiore complessità per quelle classi che implementano IList <>? Le proprietà get/set dell'indice esistono già e quelle potrebbero essere semplicemente utilizzate nel metodo Sort statico (Elenco ). – dewald

0

io non sono un esperto in C#, ma pochissime implementazioni di List supportano l'ordinamento, la ricerca binaria o persino il recupero indicizzato. Gli elenchi si basano generalmente su linked lists che di solito non offrono un modo O(1) di recuperare un elemento dal suo indice.Se si desidera individuare rapidamente un elemento, utilizzare qualcosa che mantenga gli elementi ordinati in ordine come tree o un array come suggerito da altri.

Io trovo interessante il fatto che IList include un indexed retrieval method. Potresti prendere in considerazione l'utilizzo di SortedList invece di List poiché sembra che dovrebbe supportare le ricerche per indice o chiave in tempo O(1). In generale, se hai bisogno di qualcosa che supporti la ricerca veloce, cerca una struttura dati che mantenga i suoi elementi in ordine invece di ordinarli esplicitamente. Se non altro, C# ha già la litania delle strutture dati.

+1

In C#, un "elenco" generalmente fornisce l'indicizzazione diretta degli elementi in cima a una "raccolta" che è semplicemente aggiungere/rimuovere elementi. –

+1

È possibile ordinare gli elenchi collegati in O (nlgn) con l'ordinamento di unione. –

+1

Non sono a conoscenza di alcuna implementazione di 'IList ' che utilizza l'elenco collegato come archivio. In particolare, la classe '' LinkedList 'non _non_ implementa' IList '. –

4

La buona notizia è che si può scrivere tali metodi abbastanza facilmente; e grazie a C# 3.0 metodi di estensione, si può fare questo lavoro sull'interfaccia:

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 
} 

Ora non rimane che il codice TODO stesso (e probaby riscrivere Sort ;-P); ma dopo che:

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

È importante sottolineare che, IList<T> ha un indicizzatore di lettura/scrittura, quindi è certamente possibile fare entrambe le cose del genere e binario di ricerca senza l'hack di cui sopra.

+0

@Marc: Questi sono i metodi di estensione, tuttavia, sono appena sorpreso che dobbiamo scrivere codice per eseguire queste operazioni di base. Come hai detto tu, "IList ha un indicizzatore di lettura/scrittura, quindi è certamente possibile eseguire sia la ricerca di ordinamento che di ricerca binaria senza il trucco sopra". Secondo me, questi metodi dovrebbero far parte del framework per impedire a ciascun progetto di dover creare la propria versione. – dewald

Problemi correlati