A Lista <T> garante o pedido de inserção?

238

Digamos que eu tenha três strings em uma lista (por exemplo, "1", "2", "3").

Quero reorganizá-los para colocar "2" na posição 1 (por exemplo, "2", "1", "3").

Estou usando este código (definindo indexToMoveTo como 1):

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

Isso parece funcionar, mas ocasionalmente estou obtendo resultados estranhos; Às vezes, o pedido está incorreto ou os itens da lista estão sendo excluídos!

Alguma ideia? O List<T>pedido de garantia?

Palavras-chave:

Uma Lista <T> garante que os itens serão devolvidos na ordem em que foram adicionados?

SuperSuperDev1234
fonte
3
Isso não é verdade, como mencionado aqui: stackoverflow.com/a/1790318/696517
jrmgx

Respostas:

311

A List<>classe garante a ordem - as coisas serão retidas na lista na ordem em que você as adicionar, incluindo duplicatas, a menos que você classifique explicitamente a lista.

De acordo com o MSDN:

... Lista "Representa uma lista fortemente digitada de objetos que podem ser acessados pelo índice ."

Os valores do índice devem permanecer confiáveis ​​para que isso seja preciso. Portanto, o pedido é garantido.

Você pode estar obtendo resultados ímpares do seu código se estiver movendo o item posteriormente na lista, pois você Remove()moverá todos os outros itens para um lugar antes da chamada Insert().

Você pode resumir seu código em algo pequeno o suficiente para postar?

Bevan
fonte
63
Para qualquer pesquisador futuro, aqui está a citação exata do MSDN (negrito) para List (T) .Add O objeto a ser adicionado ao final da Lista <T>. O valor pode ser nulo para tipos de referência.
Aolszowka 5/05
4
Existe uma cotação / referência mais definitiva que poderíamos obter da Microsoft ou da especificação C # sobre isso? A citação de @ aolszowka definitivamente parece sugerir que ela retém o pedido de inserção, mas tecnicamente a Lista poderia reordenar a coleção a qualquer momento após a adição de um item e essa declaração ainda seria válida. Não quero ser exigente quanto a isso, mas se um gerente ou um controle de qualidade realmente me fizesse defender essa posição, não me sentiria muito confiante com apenas essa citação.
TehDorf 17/07/2015
4
Posso pensar em duas maneiras úteis de obter alguma confirmação. Primeiro, leia a fonte e satisfaça-se. Em segundo lugar, verifique a definição do tipo de dado abstrato Listem qualquer bom livro de ciência da computação. Assim como Queuee Stack, a Listé uma estrutura de dados bem definida, previsível e bem compreendida - se a implementação do .NET diferisse (ou se mudasse) muitos softwares quebrariam.
Bevan
@tehDorf Minha opinião (se houver uma discussão sobre isso) é: "Se a ordem afeta a operação do seu método / algoritmo, você deve solicitar explicitamente a lista ou fazer com que sua API faça a interface / classe apropriada, como IOrderedEnumerable ou SortedList, caso contrário, você não deve confiar em uma implementação específica para se comportar de uma determinada maneira, a menos que seja explicitamente declarada sem ambiguidade "Você também deve ter cuidado ao classificar explicitamente a List <T>, pois sua implementação usa uma classificação instável.
aolszowka
1
@achuthakrishnan São questões separadas. A lista garante que os itens sejam retidos na ordem em que foram adicionados à lista. Ao usar o Where()método LINQ para filtrar a lista, você conta com a implementação para considerar os itens na sequência em ordem. Acontece que sim (consulte sourcesource.microsoft.com/System.Core/System/Linq/… ), mas isso não está documentado no MSDN. Eu sugiro usar emp.LastOrDefault(x => x.empDept = 'abc')como a documentação de LastOrDefault()indica que mantém a ordem dos itens.
Bevan
36

Aqui estão 4 itens, com seu índice

0  1  2  3
K  C  A  E

Você deseja mover K para entre A e E - você pode pensar na posição 3. Você deve ter cuidado com a indexação aqui, porque após a remoção, todos os índices são atualizados.

Então você remove o item 0 primeiro, deixando

0  1  2
C  A  E

Então você insere em 3

0  1  2  3
C  A  E  K

Para obter o resultado correto, você deveria ter usado o índice 2. Para tornar as coisas consistentes, você precisará enviar para (indexToMoveTo-1) if indexToMoveTo > indexToMove, por exemplo

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

Isso pode estar relacionado ao seu problema. Observe que meu código não foi testado!

EDIT : Como alternativa, você poderia Sortcom um comparador personalizado ( IComparer) se isso for aplicável à sua situação.

Joel Goodwin
fonte
Não li a resposta de Bevan com atenção suficiente, acabei de cobrir o terreno que ele tem.
Joel Goodwin
9
Sim, mas você elaborou e deu um exemplo da resposta de Bevan, bem como algum código de solução, para que sua resposta não seja tautológica e eu votei em você.
Jason S
9

Como Bevan disse, mas lembre-se de que o índice de lista é baseado em 0. Se você deseja mover um elemento para a frente da lista, é necessário inseri-lo no índice 0 (não 1, como mostrado no seu exemplo).

M4N
fonte
1

Este é o código que tenho para mover um item para um local da 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;
 }

e isso para movê-lo um lugar para cima:

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é ListBoxclaro que a lista é a ListBox.ObjectCollection, não a List<T>, mas ela é herdada e, IListportanto, deve se comportar da mesma maneira. Isso ajuda?

É claro que o primeiro só funciona se o item selecionado não for o último item da lista e o último se o item selecionado não for o primeiro item.

ChrisF
fonte
1

Se você alterar a ordem das operações, evitará o comportamento estranho: primeiro insira o valor no lugar certo na lista e, em seguida, exclua-o da primeira posição. Exclua-o pelo índice dele, porque se você o excluir por referência, poderá excluir os dois ...

Asaf
fonte