Ne kadar Hızlı bir listeden Öğeleri Kaldırmak için
Bir şekilde hızlı bir şekilde C# List<T>
öğeleri kaldırmak için arıyorum. Belgeleri List.Remove()
List.RemoveAt()
işlemleri O(n)
her ikisi de belirtiyor
Bu uygulama ciddi bir şekilde etkiliyor.
Birkaç farklı kaldırmak için bir yöntem yazdım ve tüm 500,000 List<String>
bir öğe onları test. Test durumları aşağıda gösterilmiştir
Genel bakış
Basitçe her sayının dize halinde temsilini içeren dizeleri bir listesini oluşturmak için bir yöntem yazdım("1", "2", "3", ...). Ben o zaman remove
listedeki her 5 öğe çalıştı. İşte bu yöntem, liste oluşturmak için kullanılır:
private List<String> GetList(int size)
{
List<String> myList = new List<String>();
for (int i = 0; i < size; i )
myList.Add(i.ToString());
return myList;
}
Test 1: () RemoveAt
Burada RemoveAt()
yöntemi test etmek için kullanılan test.
private void RemoveTest1(ref List<String> list)
{
for (int i = 0; i < list.Count; i )
if (i % 5 == 0)
list.RemoveAt(i);
}
Test 2: () Çıkarın
Burada Remove()
yöntemi test etmek için kullanılan test.
private void RemoveTest2(ref List<String> list)
{
List<int> itemsToRemove = new List<int>();
for (int i = 0; i < list.Count; i )
if (i % 5 == 0)
list.Remove(list[i]);
}
Test 3: Ayarlamak null, sıralama, RemoveRange
Bu test, liste üzerinde bir keresinde sarhoş ve to-be-kaldırıldı 20 ** için öğeleri ayarlayın. O zaman, listenin en üstünde olacak yani null () sıralanmış, ve null olarak ayarlanan üstündeki tüm öğeleri kaldırıldı. NOT: doğru sırayla geri koymak gitmem gerekebilir o yüzden Bu listemi yeniden,.
private void RemoveTest3(ref List<String> list)
{
int numToRemove = 0;
for (int i = 0; i < list.Count; i )
{
if (i % 5 == 0)
{
list[i] = null;
numToRemove ;
}
}
list.Sort();
list.RemoveRange(0, numToRemove);
// Now they're out of order...
}
Test 4: yeni bir liste Oluşturun ve "yeni liste . değerleri iyi tüm Ekle
Bu test, yeni bir liste oluşturdum ve benim tüm öğeleri tutmak yeni listeye eklendi. Daha sonra, orijinal listesine tüm bu maddeler koydum.
private void RemoveTest4(ref List<String> list)
{
List<String> newList = new List<String>();
for (int i = 0; i < list.Count; i )
{
if (i % 5 == 0)
continue;
else
newList.Add(list[i]);
}
list.RemoveRange(0, list.Count);
list.AddRange(newList);
}
Test 5: null ve sonra FindAll()
Bu test,--silinen tüm null
null
olmayan tüm öğeleri bulmak için FindAll()
özelliği kullanılan öğeleri ayarlayın
private void RemoveTest5(ref List<String> list)
{
for (int i = 0; i < list.Count; i )
if (i % 5 == 0)
list[i] = null;
list = list.FindAll(x => x != null);
}
Test 6: null ve sonra RemoveAll()
Bu test,--silinen tüm null
null
tüm öğeleri kaldırmak için RemoveAll()
özelliği kullanılan öğeleri ayarlayın
private void RemoveTest6(ref List<String> list)
{
for (int i = 0; i < list.Count; i )
if (i % 5 == 0)
list[i] = null;
list.RemoveAll(x => x == null);
}
İstemci Uygulama ve Çıkışlar
int numItems = 500000;
Stopwatch watch = new Stopwatch();
// List 1...
watch.Start();
List<String> list1 = GetList(numItems);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
watch.Reset(); watch.Start();
RemoveTest1(ref list1);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
Console.WriteLine();
// List 2...
watch.Start();
List<String> list2 = GetList(numItems);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
watch.Reset(); watch.Start();
RemoveTest2(ref list2);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
Console.WriteLine();
// List 3...
watch.Reset(); watch.Start();
List<String> list3 = GetList(numItems);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
watch.Reset(); watch.Start();
RemoveTest3(ref list3);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
Console.WriteLine();
// List 4...
watch.Reset(); watch.Start();
List<String> list4 = GetList(numItems);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
watch.Reset(); watch.Start();
RemoveTest4(ref list4);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
Console.WriteLine();
// List 5...
watch.Reset(); watch.Start();
List<String> list5 = GetList(numItems);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
watch.Reset(); watch.Start();
RemoveTest5(ref list5);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
Console.WriteLine();
// List 6...
watch.Reset(); watch.Start();
List<String> list6 = GetList(numItems);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
watch.Reset(); watch.Start();
RemoveTest6(ref list6);
watch.Stop(); Console.WriteLine(watch.Elapsed.ToString());
Console.WriteLine();
Sonuçları
00:00:00.1433089 // Create list
00:00:32.8031420 // RemoveAt()
00:00:32.9612512 // Forgot to reset stopwatch :(
00:04:40.3633045 // Remove()
00:00:00.2405003 // Create list
00:00:01.1054731 // Null, Sort(), RemoveRange()
00:00:00.1796988 // Create list
00:00:00.0166984 // Add good values to new list
00:00:00.2115022 // Create list
00:00:00.0194616 // FindAll()
00:00:00.3064646 // Create list
00:00:00.0167236 // RemoveAll()
Notlar Ve Yorumlar
İlk iki test aslında bu liste her kaldırdıktan sonra yeniden olduğu için listeden her 5 öğe kaldırmayın. 500.000 öğeleri dışarı aslında, sadece 83,334 (100,000 olmalıydı) çıkarıldı. Bu benim için sorun değil - açıkça Kaldır()/RemoveAt() yöntemleri iyi bir fikir zaten.
Listeden 5 öğe kaldırmak için çalıştı, ancakgerçeklikböyle bir kalıp yok olacaktır. Kaldırılacak kayıt rastgele olacak.
Bu örnekte
List<String>
kullandım, ancak bu her zaman böyle olmayacak.List<Anything>
olabilirListedeki öğeleri ile başlamak koyarak değildeğilbir seçenek.
Diğer yöntemler (3 - 6) çok daha iyi bir performansnispetenancak 3, 5, ve 6-biraz endişeliyim
null
için bir değer ayarlayın ve tüm öğeleri kaldırmak için bu sentinel göre zorlandım. Listedeki öğelerinull
olabilir bir senaryo hayal edebiliyorum ve yanlışlıkla görevden almak olurdu çünkü bu yaklaşım sevmiyorum.
Hızlı List<T>
birçok öğeleri kaldırmak için en iyi yolu Nedir? benim sorum: Denedim yaklaşımlar çoğu benim için gerçekten çok çirkin ve tehlikeli, bak. List
bir yanlış veri yapısı nedir?
Şu anda, yeni bir liste oluşturmak ve yeni liste için iyi öğeleri ekleyerek doğru eğilerek duyuyorum, ama daha iyi bir yolu olmalı gibi görünüyor.
CEVAP
Liste temizleme için geldiğinde etkili bir veri yapısı değildir. Temizleme sadece bitişik girişleri referans güncellemeleri gerektirir olarak daha iyi çift bağlantılı liste (LinkedList) kullanmak iyi olacaktır.
SERİ bir listeden öğeleri kaldırmak iç...
Nasıl üzerinde yineleme sırasında gene...
Nasıl Python dizin tarafından bir list...
Nasıl ınline-block öğeleri arasındaki ...
Python yineleme sırasında bir listeden...