¿List <T> garantiza el orden de inserción?

238

Digamos que tengo 3 cadenas en una lista (por ejemplo, "1", "2", "3").

Entonces quiero reordenarlos para colocar "2" en la posición 1 (por ejemplo, "2", "1", "3").

Estoy usando este código (estableciendo indexToMoveTo en 1):

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

Esto parece funcionar, pero ocasionalmente obtengo resultados extraños; ¡a veces el pedido es incorrecto o se eliminan elementos de la lista!

¿Algunas ideas? ¿ List<T>Garantiza el orden?

Relacionado:

¿Una Lista <T> garantiza que los artículos serán devueltos en el orden en que se agregaron?

SuperSuperDev1234
fuente
3
Esto no es cierto como se menciona aquí: stackoverflow.com/a/1790318/696517
jrmgx

Respuestas:

311

La List<>clase garantiza el orden: las cosas se mantendrán en la lista en el orden en que las agregue, incluidos los duplicados, a menos que ordene explícitamente la lista.

De acuerdo con MSDN:

... Lista "Representa una lista fuertemente tipada de objetos a los que se puede acceder por índice ".

Los valores del índice deben seguir siendo confiables para que esto sea preciso. Por lo tanto, el pedido está garantizado.

Es posible que obtenga resultados extraños de su código si mueve el elemento más adelante en la lista, ya Remove()que moverá todos los demás elementos un lugar antes de la llamada Insert().

¿Puedes reducir tu código a algo lo suficientemente pequeño como para publicar?

Bevan
fuente
63
Para cualquier futuro jugador de Google, aquí está la cita exacta del MSDN (mina en negrita) para la Lista (T). Agregue el objeto que se agregará al final de la Lista <T>. El valor puede ser nulo para los tipos de referencia.
aolszowka 05 de
44
¿Hay una cita / referencia más definitiva que podamos obtener de Microsoft o la especificación C # sobre esto? La cita de @ aolszowka definitivamente parece sugerir que retiene el orden de inserción, pero técnicamente la Lista podría reordenar la colección en cualquier momento después de agregar un elemento y esa declaración aún sería válida. No quiero ser quisquilloso al respecto, pero si un gerente o un QA realmente me hicieran defender esta posición, no me sentiría muy confiado con solo esa cita.
tehDorf
44
Se me ocurren dos formas útiles para obtener alguna confirmación. Primero, lee la fuente y satisfacete. En segundo lugar, consulte la definición del tipo de datos abstractos Listen cualquier buen libro de texto de informática. Al igual que Queuey Stack, a Listes una estructura de datos bien definida, predecible y bien entendida, si la implementación de .NET difería (o si cambia) , se rompería una gran cantidad de software.
Bevan
@tehDorf Mi opinión al respecto (si hubiera una discusión al respecto) es: "Si el orden afecta el funcionamiento de su método / algoritmo, debe ordenar explícitamente la lista o hacer que su API tome la interfaz / clase apropiada, como IOrderedEnumerable o SortedList, de lo contrario, no debe confiar en una implementación particular para que se comporte de cierta manera a menos que se indique explícitamente sin ambigüedades "También debe tener cuidado al ordenar explícitamente List <T> ya que su implementación utiliza una ordenación inestable.
aolszowka
1
@achuthakrishnan Son cuestiones separadas. La lista garantiza que los artículos se retienen en el orden en que se agregan a la lista. Cuando utiliza el Where()método LINQ para filtrar la lista, confía en la implementación para considerar los elementos de la secuencia en orden. Sucede que sí (consulte referencesource.microsoft.com/System.Core/System/Linq/… ), pero esto no está documentado en MSDN. Sugeriría usar emp.LastOrDefault(x => x.empDept = 'abc')como la documentación de LastOrDefault()sí indica que mantiene el orden de los artículos.
Bevan
36

Aquí hay 4 artículos, con su índice

0  1  2  3
K  C  A  E

Desea mover K entre A y E; puede pensar en la posición 3. Debe tener cuidado con su indexación aquí, porque después de la eliminación, todos los índices se actualizan.

Entonces eliminas el artículo 0 primero, dejando

0  1  2
C  A  E

Luego inserta a las 3

0  1  2  3
C  A  E  K

Para obtener el resultado correcto, debería haber usado el índice 2. Para hacer las cosas consistentes, deberá enviar a (indexToMoveTo-1) if indexToMoveTo > indexToMove, por ejemplo

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

Esto puede estar relacionado con su problema. ¡Tenga en cuenta que mi código no ha sido probado!

EDITAR : Alternativamente, podría Sorthacerlo con un comparador personalizado ( IComparer) si eso es aplicable a su situación.

Joel Goodwin
fuente
No leí la respuesta de Bevan con suficiente cuidado, acabo de cubrir el terreno que él tiene.
Joel Goodwin
99
Sí, pero has elaborado y dado un ejemplo de la respuesta de Bevan, así como un código de solución, por lo que tu respuesta no es tautóloga y te he votado.
Jason S
9

Como dijo Bevan, pero tenga en cuenta que el índice de lista está basado en 0. Si desea mover un elemento al principio de la lista, debe insertarlo en el índice 0 (no 1 como se muestra en su ejemplo).

M4N
fuente
1

Este es el código que tengo para mover un elemento hacia abajo un lugar en una lista:

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;
 }

y esto para moverlo un lugar hacia arriba:

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;
}

folderImageses un ListBox, por lo tanto, la lista es un ListBox.ObjectCollection, no un List<T>, pero hereda de, IListpor lo que debería comportarse igual. ¿Esto ayuda?

Por supuesto, el primero solo funciona si el elemento seleccionado no es el último elemento de la lista y el segundo si el elemento seleccionado no es el primer elemento.

ChrisF
fuente
1

Si cambia el orden de las operaciones, evitará el comportamiento extraño: primero inserte el valor en el lugar correcto de la lista y luego bórrelo de su primera posición. Asegúrese de eliminarlo por su índice, porque si lo eliminará por referencia, podría eliminarlos a ambos ...

Asaf
fuente