2009-03-07 26 views
18

List<T> listesinde yer tutucu liste değişkeni kullanmadan alternatif (tek indeksli veya çift indeksli) öğeleri kaldırmanın en etkili yolu nedir?Listede alternatif elemanların kaldırılması <T>

Ayrıca, cevabınızın her birinden maliyete değinebilirseniz memnun oluruz.

Sana alternatif ile ne demek emin değilim ama önceden

+0

Tam olarak ne anlama geliyor? –

+0

Diğer tüm öğeleri, yani tüm çift indeksleri veya tüm tek-indeks öğelerini kaldırmak mı istiyorsunuz? –

+0

evet, eşit endeksli veya tek indeksli elemanlar. – abhilash

cevap

25

Eğer çok fazla veri hareketli olacak kaldırmak üzerinde olacaktır. en verimli, daha sonra birlikte saklamak istediğiniz öğeleri taşımak sonunda kullanılmayan öğeleri kaldırmaktır:

int pos = 0; 
for (int i = 0; i < values.Count; i += 2, pos++) { 
    values[pos] = values[i]; 
} 
values.RemoveRange(pos, values.Count - pos); 

Düzenleme:
Bu yöntem 15 ms bir milyon ints bir listesini işleyecektir. Kullanılması RemoveAt o ... üç dakika boyunca

EDIT2 alacak:
Aslında pos ile başlayabileceğini = 1 ve i = 2 (veya 3), ilk öğe kendisine kopyalanması olmadığı için. Bu, kodu biraz daha az belirgin hale getirir.

+1

Bence bu sadece listedeki elemanların sayısı eşit olduğunda işe yarayacak. – tvanfosson

+0

Sadece 1 değil 0 başlatmak gerekiyor düşünüyorum, bu kod çalışacaktır – AnthonyWJones

+0

@tvanfosson: Hayır, kodun hem çift sayı hem de tek sayı için çalıştığını doğruladım. @AnthonyWJones: Çift sayıları tekil yerine kaldırmak istiyorsanız, 0 yerine – Guffa

2

bu

Teşekkür yapmak için bir verimli yolu arıyorum siz "her öğeyi" Aşağıdaki kod demek eğer çalışacak. Daha sonra 2 elemanı, 4 kaldırmaya başlayın ve böylece her öğe için RemoveAt ararsanız

List<T> list = GetTheList(); 
int i = 1; 
while (i < list.Count) { 
    list.RemoveAt(i); 
    i++; 
} 
+0

Başlangıçta bir elemanı çıkardığınızda, kalan her şey bir tane aşağı kayar. Bu kesinlikle alternatif öğeleri ortadan kaldırmaz ve muhafızın her adımda, yani listede yeniden hesaplanıp hesaplanmadığına bağlı olarak bir istisna ile sonuçlanabilir. – tvanfosson

+0

@tvanfonsson: Kod bana iyi görünüyor mu? – AnthonyWJones

+0

@Anthony - öğeyi konum 2'de kaldırdığınızda, 3 konumundaki öğe 2, 4 vardiya 3, vb. Olarak değişir, böylece kaldırılan bir sonraki öğe aslında değil, orijinal listede 5 konumundaydı. 4. – tvanfosson

7

Sadece bu yapabileceğini bir liste eski ile yeni bir liste oluşturur bir çözümün değerlendirilmesi için: Açıkçası

var newList = l.Where((_, i) => i%2 == 0).ToList(); 

var newList = old.Where((_, i) => i%2 != 0).ToList(); 

ya, seçtiğiniz münavebe bağlı.

DÜZENLEME

cevabı biraz daha hızlıdır. Burada başka bir şey okursanız, bir haftasonunda ölçtüğümden ve hafta sonunun beyninin komik olmasından kaynaklanır. :( Kapatma çözümü yanıt uygulaması yaklaşık% 40 daha hızlıdır.Yükseklikteki 2 sipariş daha hızlıdır.Gerçekten listenizin ne kadar büyük olduğuna bağlı olacağını sanıyorum!

+0

Sanırım orada F # kodu koydunuz :) – JaredPar

+0

Söylediğinizden emin değil misiniz? Bu ironically? Kesinlikle C# kodu, buraya göndermeden önce denedim. Açıkçası, bu herhangi bir temsilcisi almadım biraz şaşırıyorum, tüm bu en basit yanıtı ... – flq

+0

Bu OP gereksinimleri hiçbiri yanıt vermiyor. Bu kodun listede bulunmadığı öğeleri listeden kaldırmak istiyor. Bu kodun da sunmadığı bir performans istiyor. –

5

Ve Frank'ınkine benzer başka bir seçenek kapanışları kullanımı. Ve Frank'in sürümü daha hızlıdır.

bool isEven = true;    
var newList = list.Where(x => isEven = !isEven).ToList(); 
1
for (int i=myList.length-1; i >= 0; i--) 
    if (i % 2 == 0) 
    myList.Remove(myList[i]); 
0

genellikle STL kaplar için kullanılan standart desen kullanmak. bir silme ardından kaldırmayı yapın.

Bu şekilde size olmayacak Bu modeli görmek için kullanılan insanları karıştırmayın.

template<typename T> 
struct RemoveEven 
{ 
    RemoveEven():count(0) {} 
    bool operator()(T const&) 
    { 
     bool result = count%2 == 0; 
     count++; 
     return result; 
    } 
    private: 
     std::size_t count; 
}; 
int main() 
{ 
    std::list<int> a; 
    a.erase(std::remove_if(a.begin(),a.end(),RemoveEven<int>()),a.end()); 

} 
1

Açıkçası kullanım bağımlı, ama sen 2 oranında verin endeksi çoğaltır ve 1/2 (elided ayrıntıları) olmak listenin uzunluğunu bildiren bir sarıcı IList olabilir. Bu O (1).

+0

Zeki! Ama kırılgan. –

2

Nirvana'nın yolu ertelenmiş yürütme ile döşeniyor. Ya da başka birşey.

public static IEnumerable<T> AlternateItems<T>(this IEnumerable<T> source) 
    { 
     while (source.Any()) 
     { 
      yield return source.First(); 

      source = source.Skip(1); 

      if (source.Any()) source = source.Skip(1);     
     } 
    } 

Bu, yalnızca IList<> değil, tüm sıralamalar için geçerlidir. İterasyonun maliyeti iterasyona kadar ertelenir, ki bu büyük bir kazanç olabilir, sonuçta listedeki tüm unsurlara dokunmanıza gerek yoktur.

Basit testlerimde, tüm liste üzerinde yinelediğinizde performans çok iyi değil, bu yüzden gerçek durumunuzu mutlaka izleyin.