SORU
3 AĞUSTOS 2011, ÇARŞAMBA


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> olabilir

  • Listedeki öğ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 öğeleri null 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
3 AĞUSTOS 2011, ÇARŞAMBA


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.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • BroadCity

    BroadCity

    10 ŞUBAT 2010
  • Charles Nesson

    Charles Ness

    27 NİSAN 2006
  • Top10Series

    Top10Series

    26 Kasım 2008