List <T> garantisce l'ordine di inserimento?


238

Supponiamo di avere 3 stringhe in un elenco (ad es. "1", "2", "3").

Quindi voglio riordinarli per posizionare "2" in posizione 1 (ad es. "2", "1", "3").

Sto usando questo codice (impostando indexToMoveTo su 1):

listInstance.Remove(itemToMove);
listInstance.Insert(indexToMoveTo, itemToMove);

Questo sembra funzionare, ma ogni tanto sto ottenendo strani risultati; a volte l'ordine non è corretto o gli elementi dell'elenco vengono eliminati!

Qualche idea? Fa List<T>ordine garanzia?

Relazionato:

Un Elenco <T> garantisce che gli articoli saranno restituiti nell'ordine in cui sono stati aggiunti?


3
Questo non è vero, come indicato qui: stackoverflow.com/a/1790318/696517
jrmgx

Risposte:


311

La List<>classe garantisce l'ordinamento: le cose verranno mantenute nell'elenco nell'ordine in cui le aggiungi, inclusi i duplicati, a meno che non specifichi esplicitamente l'elenco.

Secondo MSDN:

... Elenco "Rappresenta un elenco fortemente tipizzato di oggetti a cui è possibile accedere tramite indice ."

I valori dell'indice devono rimanere affidabili affinché questo sia accurato. Pertanto l'ordine è garantito.

Potresti ottenere risultati strani dal tuo codice se sposti l'elemento più avanti nell'elenco, poiché Remove()sposterai tutti gli altri elementi in basso di un posto prima della chiamata a Insert().

Puoi ridurre il tuo codice a qualcosa di abbastanza piccolo da pubblicare?


63
Per eventuali googler futuri ecco la citazione esatta da MSDN (grassetto mio) per List (T). Aggiungi L'oggetto da aggiungere alla fine dell'elenco <T>. Il valore può essere nullo per i tipi di riferimento.
aolszowka,

4
C'è un preventivo / riferimento più definitivo che potremmo ottenere da Microsoft o dalle specifiche C # su questo? La citazione di @ aolszowka sembra sicuramente suggerire che mantiene l'ordine di inserimento, ma tecnicamente la Lista potrebbe riordinare la raccolta in qualsiasi momento dopo l'aggiunta di un articolo e tale dichiarazione sarebbe comunque valida. Non voglio essere schizzinoso a riguardo, ma se un manager o un QA mi facessero davvero difendere questa posizione, non mi sentirei molto fiducioso solo con quella citazione.
Teorf

4
Mi vengono in mente due modi utili per ottenere una conferma. Per prima cosa, leggi la fonte e soddisfa te stesso. In secondo luogo, controlla la definizione del tipo di dati astratto Listin qualsiasi buon libro di testo di informatica. Proprio come Queuee Stack, a Listè una struttura di dati ben definita, prevedibile e ben compresa - se l'implementazione di .NET differiva (o se cambia) un sacco di software si spezzerebbe.
Bevan,

@tehDorf Il mio punto di vista (se ci fosse una discussione su di esso) è: "Se l'ordinamento influisce sul funzionamento del metodo / algoritmo, è necessario ordinare esplicitamente l'elenco o fare in modo che l'API prenda l'interfaccia / classe appropriata come IOrderedEnumerable o SortedList, altrimenti non dovresti fare affidamento su una particolare implementazione per comportarti in un certo modo a meno che non sia esplicitamente dichiarato in modo inequivocabile "Devi anche fare attenzione a ordinare esplicitamente List <T> poiché la loro implementazione utilizza un ordinamento instabile.
aolszowka,

1
@achuthakrishnan Sono problemi separati. L'elenco garantisce che gli articoli vengano conservati nell'ordine in cui vengono aggiunti all'elenco. Quando si utilizza il Where()metodo LINQ per filtrare l'elenco, si fa affidamento sull'implementazione per considerare gli elementi nella sequenza in ordine. Succede che lo faccia (consultare riferimentiource.microsoft.com/System.Core/System/Linq/… ), ma questo non è documentato in MSDN. Suggerirei di usare emp.LastOrDefault(x => x.empDept = 'abc')come la documentazione di LastOrDefault()indica che mantiene l'ordine degli articoli.
Bevan,

36

Ecco 4 articoli, con il loro indice

0  1  2  3
K  C  A  E

Volete spostare K tra A ed E - potreste pensare la posizione 3. Qui state attenti all'indicizzazione, perché dopo la rimozione, tutti gli indici vengono aggiornati.

Quindi rimuovi prima l'elemento 0, lasciando

0  1  2
C  A  E

Quindi si inserisce in 3

0  1  2  3
C  A  E  K

Per ottenere il risultato corretto, avresti dovuto utilizzare l'indice 2. Per rendere le cose coerenti, dovrai inviare a (indexToMoveTo-1) if indexToMoveTo > indexToMove, ad es.

bool moveUp = (listInstance.IndexOf(itemToMoveTo) > indexToMove);
listInstance.Remove(itemToMove);
listInstance.Insert(indexToMoveTo, moveUp ? (itemToMoveTo - 1) : itemToMoveTo);

Questo potrebbe essere correlato al tuo problema. Nota il mio codice non è testato!

EDIT : in alternativa, è possibile Sortcon un comparatore personalizzato ( IComparer) se è applicabile alla propria situazione.


Non ho letto abbastanza attentamente la risposta di Bevan, ho appena coperto il terreno che ha.
Joel Goodwin,

9
Sì, ma hai elaborato e fornito un esempio della risposta di Bevan, nonché un codice di soluzione, quindi la tua risposta non è tautologa e ti ho votato.
Jason S,

9

Come ha detto Bevan, ma tieni presente che l'indice della lista è basato su 0. Se vuoi spostare un elemento in cima all'elenco, devi inserirlo nell'indice 0 (non 1 come mostrato nel tuo esempio).


1

Questo è il codice che ho per spostare un oggetto in basso di una posizione in un elenco:

if (this.folderImages.SelectedIndex > -1 && this.folderImages.SelectedIndex < this.folderImages.Items.Count - 1)
{
    string imageName = this.folderImages.SelectedItem as string;
    int index = this.folderImages.SelectedIndex;

    this.folderImages.Items.RemoveAt(index);
    this.folderImages.Items.Insert(index + 1, imageName);
    this.folderImages.SelectedIndex = index + 1;
 }

e questo per spostarlo di un posto in alto:

if (this.folderImages.SelectedIndex > 0)
{
    string imageName = this.folderImages.SelectedItem as string;
    int index = this.folderImages.SelectedIndex;

    this.folderImages.Items.RemoveAt(index);
    this.folderImages.Items.Insert(index - 1, imageName);
    this.folderImages.SelectedIndex = index - 1;
}

folderImagesè ListBoxovviamente quindi l'elenco è un ListBox.ObjectCollection, non un List<T>, ma eredita da IListquindi dovrebbe comportarsi allo stesso modo. questo aiuta?

Naturalmente il primo funziona solo se l'elemento selezionato non è l'ultimo nell'elenco e il secondo se l'elemento selezionato non è il primo.


1

Se cambierai l'ordine delle operazioni, eviterai lo strano comportamento: prima inserisci il valore nel posto giusto nell'elenco, quindi cancellalo dalla sua prima posizione. Assicurati di eliminarlo dal suo indice, perché se lo eliminerai per riferimento, potresti eliminarli entrambi ...

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.