Гарантирует ли List <T> порядок вставки?

238

Скажем, у меня есть 3 строки в списке (например, «1», «2», «3»).

Затем я хочу изменить их порядок, чтобы поместить «2» в положение 1 (например, «2», «1», «3»).

Я использую этот код (установка indexToMoveTo в 1):

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

Кажется, это работает, но я иногда получаю странные результаты; иногда порядок неправильный или элементы из списка удаляются!

Любые идеи? List<T>Гарантирует ли заказ?

Связанный:

Гарантирует ли List <T>, что предметы будут возвращены в порядке их добавления?

SuperSuperDev1234
источник
3
Это не так, как упомянуто здесь: stackoverflow.com/a/1790318/696517
jrmgx

Ответы:

311

List<>Класс делает гарантийный заказ - вещи будут сохранены в списке в порядке их добавления, включая дубликаты, если вы явно сортировки списка.

По данным MSDN:

... Список "Представляет строго типизированный список объектов, к которым можно получить доступ по индексу ."

Значения индекса должны оставаться надежными, чтобы это было точным. Поэтому заказ гарантирован.

Возможно, вы получите странные результаты из своего кода, если будете перемещать элемент позже в списке, поскольку Remove()все остальные элементы будут перемещены вниз на одно место перед вызовом Insert().

Можете ли вы свести свой код к чему-то достаточно маленькому для публикации?

Беван
источник
63
Для любого будущего гуглера здесь есть точная цитата из MSDN (выделение жирным шрифтом) для List (T). Добавить Объект, который будет добавлен в конец List <T>. Значение может быть нулевым для ссылочных типов.
aolszowka
4
Есть ли более точная цитата / ссылка, которую мы могли бы получить от Microsoft или спецификации C # по этому поводу? Цитата @ aolszowka определенно предполагает, что она сохраняет порядок вставки, но технически Список может переупорядочить коллекцию в любое время после добавления элемента, и это утверждение все еще будет действительным. Я не хочу быть придирчивым к этому, но если бы менеджер или QA действительно заставили меня защищать эту позицию, я бы не чувствовал себя очень уверенно только с этой цитатой.
tehDorf
4
Я могу придумать два полезных способа получить некоторое подтверждение. Сначала прочитайте источник и убедитесь сами. Во-вторых, проверьте определение абстрактного типа данных Listв любом хорошем учебнике по информатике. Точно так же, как Queueи Stack, a Listявляется четко определенной, предсказуемой и хорошо понятной структурой данных - если реализация .NET будет отличаться (или если она изменится), много программного обеспечения сломается
Беван
@tehDorf Мое мнение (если речь пойдет об этом): «Если упорядочение влияет на работу вашего метода / алгоритма, вы должны явно упорядочить список или сделать так, чтобы ваш API взял соответствующий интерфейс / класс, такой как IOrderedEnumerable или SortedList, в противном случае вам не следует полагаться на конкретную реализацию, которая будет вести себя определенным образом, если это явно не указано однозначно. «Также нужно быть осторожным с явной сортировкой List <T>, поскольку их реализация использует нестабильную сортировку.
aolszowka
1
@achuthakrishnan Это отдельные вопросы. Список гарантирует, что элементы сохраняются в порядке их добавления в список. Когда вы используете Where()метод LINQ для фильтрации списка, вы полагаетесь на реализацию, чтобы рассмотреть элементы в последовательности по порядку. Бывает, что так и есть (см. Referenceource.microsoft.com/System.Core/System/Linq/… ), но это не задокументировано в MSDN. Я бы посоветовал использовать emp.LastOrDefault(x => x.empDept = 'abc')в качестве документации LastOrDefault(), указывающей, что он поддерживает порядок предметов.
Беван
36

Вот 4 пункта, с их индексом

0  1  2  3
K  C  A  E

Вы хотите переместить K между A и E - вы можете подумать о позиции 3. Вы должны быть осторожны с индексированием здесь, потому что после удаления все индексы обновляются.

Таким образом, вы сначала удаляете элемент 0, оставляя

0  1  2
C  A  E

Затем вы вставляете в 3

0  1  2  3
C  A  E  K

Чтобы получить правильный результат, вы должны были использовать индекс 2. Чтобы все было согласованно, вам нужно отправить в (indexToMoveTo-1) if indexToMoveTo > indexToMove, например,

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

Это может быть связано с вашей проблемой. Обратите внимание, мой код не проверен!

РЕДАКТИРОВАТЬ : В качестве альтернативы, вы могли бы Sortс пользовательским Comparer ( IComparer), если это применимо к вашей ситуации.

Джоэл Гудвин
источник
Я недостаточно внимательно прочитал ответ Бевана, я только что рассказал о том, что у него есть.
Джоэл Гудвин
9
Да, но вы разработали и привели пример ответа Бевана, а также некоторый код решения, поэтому ваш ответ не тавтологичен, и я проголосовал за вас.
Джейсон С
9

Как сказал Беван, но имейте в виду, что индекс списка основан на 0. Если вы хотите переместить элемент в начало списка, вы должны вставить его с индексом 0 (не 1, как показано в вашем примере).

M4N
источник
1

Вот код, который у меня есть для перемещения элемента на одно место в списке:

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

и это для перемещения на одно место вверх:

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это ListBox, конечно , так что список является ListBox.ObjectCollection, а не List<T>, но он наследует от IListтак он должен вести себя так же. Это помогает?

Конечно, первый работает, только если выбранный элемент не является последним элементом в списке, и последний, если выбранный элемент не является первым элементом.

ChrisF
источник
1

Если вы измените порядок операций, вы избежите странного поведения: сначала вставьте значение в нужное место в списке, а затем удалите его с первой позиции. Убедитесь, что вы удалили его по его индексу, потому что если вы удалите его по ссылке, вы можете удалить их обоих ...

Асаф
источник