2011-09-10 9 views
5

Se si passa un IComparer personalizzato a un'istanza del metodo Sort() di una lista, il metodo Compare (x, y) del comparatore verrà mai chiamato con lo stesso elemento?Nel metodo List <T> .Sort(), un oggetto è mai paragonato a se stesso?

ie. È possibile che sia possibile chiamare Compare(x,x).

Modifica: Più interessati al caso in cui gli elementi della lista sono distinti.

+0

Certo, se l'Elenco <> contiene lo stesso oggetto più di una volta. –

+0

@Hans: Sì, mi sono confuso un po 'nel mio commento cancellato. Stavo lavorando con una lista che conteneva istanze di una classe. Naturalmente, in alcuni programmi, può anche essere possibile che la stessa istanza si verifichi più volte nell'elenco. Ma come modificato, mi chiedevo il caso in cui la lista contenesse istanze distinte della classe. – ForeverLearnNeverMaster

+0

@Hans: vedi la risposta di JohnD? – ForeverLearnNeverMaster

risposta

9

Ho scritto un programma di prova per provarlo. Sembra che in realtà fa Compare() lo stesso elemento a sé stesso (almeno Compare() viene chiamato per lo stesso elemento due volte). In questo programma, Compare() viene chiamato con argomenti (2, 2).

using System; 
using System.Collections.Generic; 

static class Program 
{ 
    class MyComparer : Comparer<int> 
    { 
     public override int Compare(int x, int y) 
     { 
      Console.WriteLine("Compare(" + x + ", " + y + ")"); 
      if (x < y) return -1; 
      if (x > y) return 1; 
      return 0; 
     } 
    } 

    static void Main() 
    { 
     MyComparer comparer = new MyComparer(); 
     List<int> list = new List<int> { 1, 2, 3 }; 
     list.Sort(comparer); 
     return; 

    } 
} 

e l'uscita è:

Compare(1, 2) 
Compare(1, 3) 
Compare(2, 3) 
Compare(1, 2) 
Compare(2, 2) 
Compare(2, 3) 
Compare(2, 2) 
+0

Hmm .. sì. Aggiunto un Console.WriteLine() all'inizio del metodo Compare(). Compare (2,2) è chiamato due volte per la lista data. – ForeverLearnNeverMaster

+0

+1 per "Ho scritto un programma di prova per provarlo." – iandisme

+0

Confermato usando Mono 2.6.7.0. (Mi sono preso la libertà di aggiungere le direttive 'using' e una' WriteLine', per rendere più facile la gente a provarci.) – Thomas

7

Dal docs:

Questo metodo utilizza Array.Sort, che utilizza l'algoritmo QuickSort.

QuickSort non confronta mai un oggetto con se stesso. Alcune implementazioni di QuickSort mettono a confronto gli oggetti. Questo può accadere anche se quell'elemento si verifica più di una volta nel tuo Elenco.

In entrambi i casi, affinché la funzione di confronto sia una funzione di confronto corretta e ben funzionante, è necessario gestire il caso di elementi confrontati a se stessi.

+0

In che modo spiega la risposta di JohnD? Mi manca qualcosa di ovvio? – ForeverLearnNeverMaster

+0

Questa risposta continua a essere votata up up v__v. Qualcuno può confermare il comportamento quicksort qui riportato, che sembra contraddire il programma di esempio di JohnD? – ForeverLearnNeverMaster

+0

Hmm, è interessante! Sono felice che entrambe le risposte appaiano in cima, ora che JohnD's è stato accettato. In tal caso, dobbiamo concludere che i documenti sono sbagliati. – Thomas

2

Sebbene non sia strettamente garantito, sono abbastanza sicuro che il metodo Sort di List non chiamerà mai il metodo di confronto per confrontare un oggetto con se stesso a meno che l'oggetto non appaia nell'elenco più volte. Baso questa conclusione sul fatto che ListSort è implementato usando l'algoritmo QuickSort (secondo MSDN), che non confronta mai di solito non comporta il confronto di lo stesso elemento a se stesso (e nessuno dei due altro ordinamento documentato algoritmi a cui riesco a pensare). (Modifica: Sembra che l'implementazione di Microsoft confronti l'elemento a se stesso. Vedere risposta accettata sopra.)

Tuttavia, una buona pratica di codifica imporrebbe che l'implementazione di IComparer debba essere in grado di gestire lo stesso oggetto in entrambi i parametri, altrimenti l'implementazione non è completa del contratto definito da IComparer. Probabilmente funzionerebbe per il tuo scenario, ma dovresti fare affidamento sui dettagli di implementazione del metodo di ordinamento (che potrebbero cambiare in futuro) e non potresti utilizzare l'implementazione di IComparer in altri scenari in cui non esiste tale garanzia (o peggio, tu o qualcun altro lo usa e probabilmente crea un bug difficile da trovare).

1

Un'altra risposta, questa volta sulla base the XML part of ECMA-335, la specifica del BCL (Base Class Library). Anche se non è garantito il collegamento con le effettive implementazioni, questo è autorevole. E la specifica non dice nient'altro:

Nel peggiore dei casi, questa operazione è O (n^2), dove n è il numero di elementi da ordinare. In media è O (n log n).

Sebbene questo sia indicativo di QuickSort, non è assolutamente garantito. Né le specifiche richiedono implementazione in termini di Array.Sort.

Bottom line: per quanto riguarda le specifiche, è perfettamente accettabile per le implementazioni di confrontare gli elementi a se stessi.

Problemi correlati