Soru Python'da bilinen bir öğeye bir liste başlatma [duplicate]


Bu sorunun zaten bir cevabı var:

Şu anda bir liste kullanıyorum ve şöyle bir şey bekliyordum:

verts = list (1000)

Bunun yerine dizi kullanmalı mıyım?


195
2018-02-06 18:58


Menşei


Önceden tanımlanmış sayıda öğe içeren bir koleksiyonu başlat. - Joan Venge
Niye ya? Öğeleri rastgele pozisyonlarda ayarlamanız mı gerekiyor? - Torsten Marek
Niye ya? Siparişin önemli olduğu eşya koleksiyonum var. Nasıl yapıldığının cevabını biliyor musunuz? Steve'in cevabı tek yol gibi görünüyor. - Joan Venge
Şaşırdım (ve @JoanVenge için biraz üzgün hissediyorum) yerlerin her yerine sapan sayı yorumları. Benim düşünceme göre, standart bir cevap önce bir görevin nasıl gerçekleştirileceğini (ne kadar saçma olursa olsun) içermeli ve sonra kullanıcıyı soruya yönlendirmeli / tavsiyede bulunmalıdır. Sadece anlamsız görünüyor. Sorunun geçerliliğini sorgulamak sorgulanabilir. - Shashank Sawant
@ShashankSawant: SO'ya hoş geldiniz. - Joan Venge


Cevaplar:


Benim için akla ilk gelen şey:

verts = [None]*1000

Ama gerçekten bunu önceden başlatmaya ihtiyacın var mı?


275
2018-02-06 19:02



Evet, tam olarak bu nokta. “Prematüre optimizasyon, tüm kötülüklerin köküdür” demek, ilk başta, performansa bakmadan kod yazmanız gerektiği anlamına gelir. Kodun daha sonra yavaş çalıştığını fark ederseniz, sonra geri dön ve bunun gibi optimizasyonlar yap. - David Z
Hayır, en iyi duruma getirme, belirli gereksinimlerin optimize edilmeyeceği bir kodu optimize etmeye çalıştığınız zamandır. Her zaman mümkün olan en hızlı kodu yazmamalısınız - iş hedefleri, bakım maliyeti, yazılacak mühendislik zamanı gibi diğer endişeler genellikle daha önemlidir. - user26294
Bir diziyi önceden ayırma isteği için optimizasyonlardan başka meşru vakalar olduğunu unutmayın. Kullanan kod, eleman eklemez, sadece mevcut olanların yerini alır, bu yüzden bir listeden daha çok bir dizi gibidir. - Lasse Vågsæther Karlsen
Bir Python dizisini başlatma yolu kötülüktür: a=[[]]*2; a[0].append('foo'); şimdi incelemek a[1]ve sen şok olacaksın. Tersine a=[[] for k in range(2)] iyi çalışıyor. - Joachim W
Varsayımlarınızı kontrol edin. Örneğin. Şu anda bir log dosyası ayrıştırmak ve şu anda 4 adet / saat ve 24 saat / gün olmak üzere bir dizi çöp kutusuna hataları koyarak bir ağ hatası oranı analiz ediyorum. Bir saatteki saatler değişmez ve eğer kutuları / saati değiştirirsem, programı durduracağım ve yeniden başlatacağım, böylece her zaman (şu anda) 4 * 24 = 96 kutu istiyorum. Her bir binayı 0'a başlatarak başlamak benim için doğaldır (C / C ++ / C # / vb arka plan ile). Bu bir optimizasyon, erken mi değil mi? - Technophile


Herkesin bunu yapmak için neden zor zamanlar verdiğini tam olarak bilmiyorum - sabit boyutlu bir başlangıç ​​listesi oluşturmak istediğiniz birkaç senaryo var. Ve bu durumlarda dizilerin mantıklı olduğunu doğru bir şekilde anladınız.

import array
verts=array.array('i',(0,)*1000)

Pythonista'lar için (0,)*1000 dönem 1000 sıfır içeren bir tuple yaratıyor. Virgül python'u tanımak için zorlar (0) Bir tuple olarak, aksi takdirde 0 olarak değerlendirilecektir.

Bir liste yerine bir tuple kullandım çünkü genellikle daha düşük bir yüke sahipler.


65
2017-12-03 03:46



Bazı insanlar gerçekten "erken" optimizasyon alırlar sanırım. - Joan Venge
Teşekkürler! Bu çözüm kesinlikle aradığım şey. Profil oluştururken, liste başlatma kodumdaki darboğazdı ve bu 2 kat daha hızlı hale getirdi. - Frederik
Ne yazık ki henüz bir "o bunu yapmak ister miydin?" Diye bir SOYUTLU Python sorusunun cevabını bulmak için henüz bir cevap buldum - standart bir cevap olarak yatakhane odası kibir yazın. Yay "topluluk". - tomtheguvnor
@mikerodent Joan, Fransa, İspanya ve Hollanda dahil olmak üzere dünyanın çeşitli ülkelerinde bir erkek ismi. - Chris
@Chris kesinlikle İspanya ve bildiğim kadarıyla N'lands. Fransa'da uzun yıllardır yaşadığından emin değilim. Sözümü biraz değiştirebilirsem, bu rahatsız edici saldırganlık tonu bazı (anglofon) "yurt odası eğlencelerinden" kaynaklanabilir. varsayarak Joan kadın olmak için. - mike rodent


Bir bariz ve muhtemelen etkili olmayan bir yoldur

verts = [0 for x in range(1000)]

Bunun 2 boyutlu olarak kolayca genişletilebileceğini unutmayın. Örneğin, bir 10x100 "dizi" almak için yapabilirsiniz

verts = [[0 for x in range(100)] for y in range(10)]

53
2017-10-28 22:41





Bir dizi sabit büyüklüğü inisiye etmek istemek, herhangi bir programlama dilinde yapılması kabul edilebilir bir şeydir; Programcı bir süre (gerçek) döngüde bir break ifadesi koymak istemiyor. Bana inanıyorum, özellikle eğer unsurlar sadece birçoğunun üzerine yazılacak ve sadece bir kaç dinamik programlama algoritması gibi eklenecek / çıkarılmayacaksa, ek açıklamalarla uğraşmak istemezsiniz ve elemanın kontrol edilip edilmediğini kontrol etmek istemezsiniz. henüz başlangıçta başlatıldı (bu kod kodları çok).

object = [0 for x in range(1000)]

Bu programcının ulaşmaya çalıştığı şey için çalışacaktır.


29
2018-03-09 20:09





@Steve zaten sorunuza iyi bir cevap verdi:

verts = [None] * 1000

Uyarı: @Joachim Wuttke'nin işaret ettiği gibi, liste değişmez bir öğe ile başlatılmalıdır. [[]] * 1000 beklendiği gibi çalışmaz, çünkü 1000 benzer listenin bir listesini alacaksınız (C listesinde aynı listeye 1000 puanlık bir listeye benzer). İnt, str veya tuple gibi ölçülebilir nesneler iyi sonuç verir.

Alternatifler

Yeniden boyutlandırma listeleri yavaş. Aşağıdaki sonuçlar çok şaşırtıcı değil:

>>> N = 10**6

>>> %timeit a = [None] * N
100 loops, best of 3: 7.41 ms per loop

>>> %timeit a = [None for x in xrange(N)]
10 loops, best of 3: 30 ms per loop

>>> %timeit a = [None for x in range(N)]
10 loops, best of 3: 67.7 ms per loop

>>> a = []
>>> %timeit for x in xrange(N): a.append(None)
10 loops, best of 3: 85.6 ms per loop

Ancak çok büyük listeleriniz yoksa yeniden boyutlandırma çok yavaş olmaz. Listeyi tek bir eleman ile başlatmak yerine (ör. None) ve listenin yeniden boyutlandırılmasını önlemek için sabit bir uzunluk, liste anlamalarını kullanmayı düşünmeli ve doğru değerleri içeren listeyi doğrudan doldurmalısınız. Örneğin:

>>> %timeit a = [x**2 for x in xrange(N)]
10 loops, best of 3: 109 ms per loop

>>> def fill_list1():
    """Not too bad, but complicated code"""
    a = [None] * N
    for x in xrange(N):
        a[x] = x**2
>>> %timeit fill_list1()
10 loops, best of 3: 126 ms per loop

>>> def fill_list2():
    """This is slow, use only for small lists"""
    a = []
    for x in xrange(N):
        a.append(x**2)
>>> %timeit fill_list2()
10 loops, best of 3: 177 ms per loop

Numpy ile karşılaştırma

Büyük veri seti için numpy veya diğer optimize edilmiş kitaplıklar çok daha hızlıdır:

from numpy import ndarray, zeros
%timeit empty((N,))
1000000 loops, best of 3: 788 ns per loop

%timeit zeros((N,))
100 loops, best of 3: 3.56 ms per loop

13
2018-01-02 23:57





Bunu yapabilirsin:

verts = list(xrange(1000))

Bu size boyut olarak 1000 elemandan oluşan bir liste verir ve bu da 0-999 arasındaki değerlerle başlatılır. Gibi list yapar __len__ İlk önce yeni listeyi boyutlandırmak için oldukça verimli olmalı.


2
2018-02-07 18:51



python 3.0'dan önce menzil (1000) olur; python 3.0'da liste olurdu (aralık (1000))


Kullanarak düşünmelisiniz dict Önceden başlatılmış liste yerine yazın. Bir sözlük aranmasının maliyeti küçüktür ve rasgele liste öğesinin erişim maliyetiyle karşılaştırılabilir.

Ve bir haritalama kullanırken şunları yazabilirsiniz:

aDict = {}
aDict[100] = fetchElement()
putElement(fetchElement(), fetchPosition(), aDict)

Ve putElement Fonksiyon herhangi bir pozisyonda eşya saklayabilir. Koleksiyonunuzun belirtilen endekste eleman içerip içermediğini kontrol etmeniz gerekirse, yazmak için daha çok Pythonic:

if anIndex in aDict:
    print "cool!"

daha:

if not myList[anIndex] is None:
    print "cool!"

İkincisi, hayır olduğunu varsayar gerçek koleksiyonunuzdaki elemanlar None. Ve eğer bu olursa - kodunuz yanlış çalışır.

Ve eğer çaresizce performansa ihtiyacınız varsa ve bu yüzden değişkenlerinizi önceden başlatmaya çalışın ve mümkün olan en hızlı kodu yazın - dilinizi değiştirin. En hızlı kod Python'da yazılamaz. Bunun yerine C'yi deneyin ve Python'dan önceden başlatılmış ve önceden derlenmiş kodunuzu çağırmak için sarmalayıcıları uygulamanız gerekir.


0
2018-02-07 18:20





Bu:

 list = [8 for i in range(9)]

bir liste oluşturur, elemanlar başlatılır 8

ama bu:

list = [0] * 7

Bir elemente sahip 7 liste oluşturur


0
2018-03-11 08:02



[0] * 7 değerlendirir [0, 0, 0, 0, 0, 0, 0]7 eleman içeren bir liste. Yoksa Python'un çok eski bir versiyonunun davranışını mı tarif ediyorsunuz? - FooF
Söylediği şey, listede 7 eleman içeriyor, ancak 7 öğenin tümü aynı belleğe işaret ediyor. Ve bu 7 unsurdan herhangi birine yapılan bir değişiklik, diğerlerinin de buna uygun olarak değişmesine yol açacaktır. - York
Öğeler tam sayıysa, değil mi? Az önce denedim mylist = [0] * 4, ondan sonra mylist[0] = 12, mylist döner [12, 0, 0, 0] - toonarmycaptain


Sorunlu alan hakkında daha fazla bilgi sahibi olmadan, sorunuza cevap vermek zordur. Daha fazla bir şey yapmanız gerektiğinden emin değilseniz, bir listeyi başlatmanın pythonik yolu:

verts = []

Aslında bir performans problemi mi görüyorsun? Eğer öyleyse, performans darboğazı nedir? Sahip olmadığınız bir sorunu çözmeye çalışmayın. Bir diziyi dinamik olarak 1000 elemanla doldurmak için performans maliyeti tamamen alakasız Yazmaya çalıştığınız programa.

Listenizdeki öğeler her zaman belirli bir ilkel sabit uzunlukta tür (ör. Char, int, float) olacaksa dizi sınıfı yararlıdır. Ancak, aynı zamanda ön başlatma gerektirmez.


-3
2018-02-06 21:05



Noktayı görmüyorsun. Önceden tanımlanmış sayıda eleman içeren bir liste / dizi oluşturmak istiyorum. Neden ve neden ihtiyaç duyduğuma dair yorum yapmak saçma. Ne yaptığımı biliyorum. Teşekkürler. - Joan Venge
Söylediğimde, ne yaptığımı biliyorum, python değil, bilge programlama demek istedim. Python'u bilseydim, soruyu sormazdım, şimdi yapar mıyım? - Joan Venge
Soruyu düzenleyebilir ve biraz daha bağlamı açıklayabilir misiniz? Sorudan, doğru cevabın ne olduğu belli değil ve aynı zamanda ne yaptığınızı bildiğiniz de net değil. - user26294