<T> Listesi kampanya siparişini garanti ediyor mu?


238

Bir Listede 3 dizgim olduğunu varsayalım (örneğin "1", "2", "3").

Sonra onları "2" yi konum 1'e yerleştirmek için yeniden sıralamak istiyorum (örn. "2", "1", "3").

Bu kodu kullanıyorum (indexToMoveTo için 1 ayarı):

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

Bu işe yarıyor gibi görünüyor, ama bazen garip sonuçlar alıyorum; bazen sipariş yanlış veya listedeki öğeler siliniyor!

Herhangi bir fikir? Does List<T>garanti sipariş?

İlişkili:

Liste <T>, öğelerin eklendikleri sırayla iade edileceğini garanti ediyor mu?


3
Bu burada belirtildiği gibi doğru değil: stackoverflow.com/a/1790318/696517
jrmgx

Yanıtlar:


311

List<>Sınıf garanti sipariş yapar - işler, çiftleri de dahil olmak üzere, bunları eklemek amacıyla listede tutulacaktır açıkça sıralama listesinde olmadıkça.

MSDN'ye göre:

... Liste "Dizine erişilebilen , güçlü bir şekilde yazılmış nesnelerin listesini temsil eder ."

Bunun doğru olması için indeks değerleri güvenilir kalmalıdır. Bu nedenle sipariş garantilidir.

Öğeyi listede daha sonra taşıyorsanız, kodunuzdan garip sonuçlar alıyor olabilirsiniz, çünkü Remove()diğer tüm öğeleri çağrıdan önce bir yere taşır Insert().

Kodunuzu gönderilecek kadar küçük bir şeye kadar kaynatır mısınız?


63
Gelecekteki herhangi bir googler için burada Liste (T) için MSDN'den (cesur maden) kesin alıntı.Add Listenin sonuna eklenecek nesne <T>. Referans türleri için değer null olabilir.
aolszowka

4
Microsoft veya bununla ilgili C # spesifikasyonundan alabileceğimiz daha kesin bir teklif / referans var mı? @ aolszowka'nın teklifi kesinlikle ekleme siparişini koruduğunu öne sürüyor, ancak teknik olarak Liste, bir öğe eklendikten sonra herhangi bir zamanda koleksiyonu yeniden sipariş edebilir ve bu ifade yine de geçerli olacaktır. Bu konuda nit seçici olmak istemiyorum, ama bir yönetici veya KG gerçekten bu pozisyonu savunmamı sağladıysa, sadece bu alıntıdan çok emin olmazdım.
tehDorf

4
Bazı onaylar almanın iki yararlı yolunu düşünebilirim. İlk olarak, kaynağı okuyun ve kendinizi tatmin edin. İkincisi, Listherhangi bir iyi bilgisayar bilimi ders kitabındaki soyut veri türünün tanımına göz atın. Tıpkı Queueve gibi Stacka List, iyi tanımlanmış, öngörülebilir ve iyi anlaşılmış bir veri yapısıdır - .NET uygulaması farklıysa (veya değişirse) çok fazla yazılım kırılır.
Bevan

@tehDorf Alışmam (üzerinde bir tartışma olacaksa): "Sipariş yönteminizin / algoritmanızın çalışmasını etkiliyorsa, listeyi açıkça sipariş etmeli veya API'nizin IOrderedEnumerable gibi uygun Arabirimi / sınıfı almasını veya SortedList, aksi takdirde açık bir şekilde açıkça belirtilmedikçe belirli bir uygulamaya güvenmek için belirli bir uygulamaya güvenmemelisiniz. "Ayrıca, uygulamaları <T> 'nin listesi kararsız bir sıralama kullandığı için açıkça <T> Listesini sıralamak konusunda da dikkatli olmalısınız.
aolszowka

1
@achuthakrishnan Bunlar ayrı konular. Liste, öğelerin listeye eklendikleri sırayla saklanacağını garanti eder. Where()Listeye filtre uygulamak için LINQ yöntemini kullandığınızda, sıradaki öğeleri sırayla dikkate almak için uygulamaya güvenirsiniz. Bu gerçekleşir (bkz. Referenceource.microsoft.com/System.Core/System/Linq/… ), ancak bu MSDN'de belgelenmemiştir. emp.LastOrDefault(x => x.empDept = 'abc')Dokümanların LastOrDefault()öğelerin sırasını koruduğunu gösterdiği için kullanmanızı öneririm .
Bevan

36

İşte dizini ile 4 madde

0  1  2  3
K  C  A  E

K'yı A ve E arasında taşımak istiyorsunuz - konum 3'ü düşünebilirsiniz. Burada indekslemenize dikkat etmelisiniz, çünkü kaldırıldıktan sonra tüm dizinler güncellenir.

Böylece ilk önce 0 öğesini kaldırıyorsunuz,

0  1  2
C  A  E

Sonra 3'te takın

0  1  2  3
C  A  E  K

Doğru sonucu elde etmek için, dizin 2'yi kullanmış olmalısınız. İşleri tutarlı hale getirmek için (indexToMoveTo-1) adresine if indexToMoveTo > indexToMove, örneğin,

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

Bu, sorununuzla ilgili olabilir. Kodumun test edilmediğini unutmayın!

EDIT : Alternatif olarak, durumunuz için geçerliyse, Sortözel bir karşılaştırıcıyla ( IComparer) yapabilirsiniz.


Bevan'ın tepkisini yeterince dikkatle okumadım, sadece sahip olduğu zemini kapladım.
Joel Goodwin

9
Evet, ama Bevan'ın cevabının yanı sıra bazı çözüm kodlarının bir örneğini hazırladınız ve verdiniz.
Jason S

9

Bevan'ın dediği gibi, ama unutmayın ki, liste endeksi 0 tabanlı. Bir öğeyi listenin önüne taşımak istiyorsanız, 0 dizinine eklemeniz gerekir (örneğinizde gösterildiği gibi 1 değil).


1

Bu, bir öğeyi listede bir yere taşımak için sahip olduğum kod:

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

ve bunu bir yere taşımak için:

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

folderImagesBir olan ListBoxliste bir nedenle elbette ListBox.ObjectCollectiondeğil, bir List<T>ama devralan gelmez IListaynı davranması gerektiğini böylece. Bu yardımcı olur mu?

Elbette birincisi sadece seçilen öğe listedeki son öğe değilse, ikincisi seçilen öğe ilk öğe değilse çalışır.


1

İşlemlerin sırasını değiştirirseniz, garip davranışı önlersiniz: Önce değeri listede doğru yere ekleyin ve ardından ilk konumundan silin. Dizini ile sildiğinizden emin olun, çünkü referans ile silerseniz, ikisini de silebilirsiniz ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.