Apakah Daftar <T> menjamin urutan penyisipan?

238

Katakanlah saya memiliki 3 string dalam Daftar (mis. "1", "2", "3").

Lalu saya ingin memesan ulang mereka untuk menempatkan "2" di posisi 1 (misalnya "2", "1", "3").

Saya menggunakan kode ini (mengatur indexToMoveTo ke 1):

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

Ini sepertinya berhasil, tetapi saya terkadang mendapatkan hasil yang aneh; terkadang pesanan salah atau item dari daftar semakin dihapus!

Ada ide? Apakah List<T>jaminan pemesanan?

Terkait:

Apakah Daftar <T> menjamin bahwa barang akan dikembalikan sesuai urutan penambahannya?

SuperSuperDev1234
sumber
3
Ini tidak benar seperti yang disebutkan di sini: stackoverflow.com/a/1790318/696517
jrmgx

Jawaban:

311

The List<>kelas tidak jaminan pemesanan - hal akan dipertahankan dalam daftar dalam urutan yang Anda menambahkannya, termasuk duplikat, kecuali Anda secara eksplisit semacam daftar.

Menurut MSDN:

... Daftar "Merupakan daftar objek yang sangat diketik yang dapat diakses oleh indeks ."

Nilai indeks harus tetap andal agar ini akurat. Oleh karena itu pesanan dijamin.

Anda mungkin mendapatkan hasil aneh dari kode Anda jika Anda memindahkan item nanti dalam daftar, karena Anda Remove()akan memindahkan semua item lain ke satu tempat sebelum panggilan ke Insert().

Bisakah Anda merebus kode menjadi sesuatu yang cukup kecil untuk dikirim?

Bevan
sumber
63
Untuk setiap googler masa depan di sini adalah kutipan yang tepat dari MSDN (bolding mine) untuk List (T). Tambahkan Objek yang akan ditambahkan ke akhir Daftar <T>. Nilai bisa nol untuk tipe referensi.
aolszowka
4
Apakah ada kutipan / referensi yang lebih pasti yang bisa kita dapatkan dari Microsoft atau spesifikasi C # tentang ini? Kutipan @ aolszowka jelas menunjukkan bahwa ia mempertahankan urutan penyisipan, tetapi secara teknis Daftar dapat memesan ulang koleksi setiap saat setelah item ditambahkan dan pernyataan itu masih valid. Saya tidak ingin bingung tentang hal itu, tetapi jika seorang manajer atau QA benar-benar membuat saya mempertahankan posisi ini, saya tidak akan merasa sangat percaya diri dengan hanya kutipan itu.
tehDorf
4
Saya dapat memikirkan dua cara yang berguna untuk mendapatkan konfirmasi. Pertama, bacalah sumbernya dan puaskan diri Anda. Kedua, periksa definisi tipe data abstrak Listdi setiap buku teks ilmu komputer yang baik. Sama seperti Queuedan Stack, a Listadalah struktur data yang terdefinisi dengan baik, dapat diprediksi dan dipahami dengan baik - jika implementasi .NET berbeda (atau jika berubah) banyak perangkat lunak akan rusak.
Bevan
@tehDorf Pandangan saya tentang hal itu (jika ada diskusi tentang hal itu) adalah: "Jika pemesanan mempengaruhi operasi metode / algoritma Anda, Anda harus secara eksplisit memesan daftar atau meminta API Anda mengambil Antarmuka / kelas yang sesuai seperti IOrderedEnumerable atau SortedList, jika tidak, Anda tidak boleh mengandalkan pada implementasi tertentu untuk berperilaku dengan cara tertentu kecuali jika secara eksplisit dinyatakan secara jelas "Anda juga harus berhati-hati dalam menyortir Daftar <T> secara eksplisit karena implementasi mereka menggunakan pengurutan yang tidak stabil.
aolszowka
1
@achuthakrishnan Mereka adalah masalah yang terpisah. Daftar menjamin bahwa barang disimpan sesuai urutan ditambahkan ke daftar. Saat Anda menggunakan Where()metode LINQ untuk memfilter daftar, Anda mengandalkan implementasi untuk mempertimbangkan item dalam urutan. Itu terjadi (lihat Referenceource.microsoft.com/System.Core/System/Linq/… ), tetapi ini tidak didokumentasikan dalam MSDN. Saya sarankan menggunakan emp.LastOrDefault(x => x.empDept = 'abc')sebagai dokumentasi LastOrDefault()tidak menunjukkan itu mempertahankan urutan barang.
Bevan
36

Berikut adalah 4 item, dengan indeksnya

0  1  2  3
K  C  A  E

Anda ingin memindahkan K ke antara A dan E - Anda mungkin berpikir posisi 3. Anda harus berhati-hati tentang pengindeksan di sini, karena setelah menghapus, semua indeks diperbarui.

Jadi Anda menghapus item 0 terlebih dahulu, pergi

0  1  2
C  A  E

Kemudian Anda masukkan pukul 3

0  1  2  3
C  A  E  K

Untuk mendapatkan hasil yang benar, Anda harus menggunakan indeks 2. Untuk membuat semuanya konsisten, Anda harus mengirim ke (indexToMoveTo-1) if indexToMoveTo > indexToMove, mis.

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

Ini mungkin terkait dengan masalah Anda. Perhatikan kode saya belum diuji!

EDIT : Atau, Anda bisa Sortmenggunakan pembanding khusus ( IComparer) jika itu berlaku untuk situasi Anda.

Joel Goodwin
sumber
Tidak membaca tanggapan Bevan dengan cukup hati-hati, saya baru saja membahas alasannya.
Joel Goodwin
9
Ya, tetapi Anda telah menguraikan dan memberikan contoh jawaban Bevan, serta beberapa kode solusi, jadi jawaban Anda tidak terlalu menarik dan saya telah memilih Anda.
Jason S
9

Seperti yang dikatakan Bevan, tetapi perlu diingat, bahwa daftar-indeks berbasis 0. Jika Anda ingin memindahkan elemen ke depan daftar, Anda harus memasukkannya di indeks 0 (bukan 1 seperti yang ditunjukkan pada contoh Anda).

M4N
sumber
1

Ini adalah kode yang saya miliki untuk memindahkan item ke satu tempat dalam daftar:

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

dan ini untuk memindahkannya satu tempat ke atas:

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

folderImagesadalah ListBoxtentu saja sehingga daftar adalah ListBox.ObjectCollection, bukan List<T>, tapi itu tidak mewarisi dari IListsehingga harus bersikap sama. Apakah ini membantu?

Tentu saja yang pertama hanya berfungsi jika item yang dipilih bukan item terakhir dalam daftar dan yang terakhir jika item yang dipilih bukan item pertama.

ChrisF
sumber
1

Jika Anda akan mengubah urutan operasi, Anda akan menghindari perilaku aneh: Pertama, masukkan nilai ke tempat yang tepat dalam daftar, dan kemudian hapus dari posisi pertama. Pastikan Anda menghapusnya dengan indeksnya, karena jika Anda akan menghapusnya dengan referensi, Anda mungkin menghapus keduanya ...

Asaf
sumber