Daha büyük bir listedeki her n'inci öğenin listesini döndürmenin pitonik yolu


172

Diyelim ki 0'dan 1000'e kadar bir sayı listemiz var. İlk ve sonraki her 10uncu maddenin bir listesini üretmenin pythonic / verimli bir yolu var mı, yani [0, 10, 20, 30, ... ]?

Evet, bunu bir for döngüsü kullanarak yapabilirim, ama bunu yapmanın daha temiz bir yolu olup olmadığını merak ediyorum, belki de bir satırda bile?

Yanıtlar:


291
>>> lst = list(range(165))
>>> lst[0::10]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]

Bunun, her bir öğe için bir modülü döngülemekten ve kontrol etmekten yaklaşık 100 kat daha hızlı olduğuna dikkat edin:

$ python -m timeit -s "lst = list(range(1000))" "lst1 = [x for x in lst if x % 10 == 0]"
1000 loops, best of 3: 525 usec per loop
$ python -m timeit -s "lst = list(range(1000))" "lst1 = lst[0::10]"
100000 loops, best of 3: 4.02 usec per loop

4
Tabii, liste kavrayışları genel olarak daha güçlüdür. OTOH, soru var olan bir listeyi ortaya koyuyor ve bu durumda bir dilim gayet iyi çalışıyor.
Ned Deily

Bunu liste anlama cevaplarında aşağıda yorumladım. "Eğer x% 10 == 0" a dikkat edin. Yalnızca bu belirli liste örneğiyle çalışır, ancak giriş listesi örneğin l = aralık (0,1000,2) ise, her 10uncu öğeyi dışarı çekmez.
Andre Miller

12
@Andre: çok doğru. Bu, alçakgönüllü bir dil özelliğinin bir örneğidir, bu durumda (1) doğru sonuçları almayı kolaylaştırmak için ortaya çıkan dilim operatörü; (2) daha kısa bir ifade ile sonuçlanır; ve (3) 2 derece daha hızlıdır. (1) elbette en önemli endişe, ama dilin dikkatli tasarımı ve uygulanması sayesinde, üçünü de 1 fiyatına alırsınız. Güzel soru ve cevaplar.
Ned Deily

2
0İçinde gereksiz l[0::10]. l[::10]daha okunabilir, daha az kafa karıştırıcı.
Konstantin Schubert

Liste kavrama için 0.5 saniye ve liste dilimi için 0.4s performans karşılaştırması ile şaşırdım. Çok yavaş görünüyor, neden liste dilimleme 1 bin boyutunda bir liste için 100 bin döngüye ihtiyaç duyuyor !?
Damo

58
  1. source_list[::10] en açık olanıdır, ancak bu yinelenebilir bir şey için işe yaramaz ve büyük listeler için bellek verimli değildir.
  2. itertools.islice(source_sequence, 0, None, 10) herhangi bir yinelenebilir için çalışır ve bellek tasarrufludur, ancak büyük liste ve büyük adım için muhtemelen en hızlı çözüm değildir.
  3. (source_list[i] for i in xrange(0, len(source_list), 10))

1
+1 En iyi cevap, IMO. Her üç teklif de genel bir çözümdür (yani kaynak listesini verilen şekilde alır). Jeneratör çözümü (3.) kaynak listesinin dizinine filtre uyguladığı için iyi. Muhtemelen 2 kadar bellek verimlidir. Hem endeksler hem de sonuç listesi jeneratörlerdir ve tembel bir şekilde inşa edilmiştir, bu da sonuç listesine tek bir parçada ihtiyacınız yoksa muhtemelen en hızlısıdır. Sadece kaynak listesi bir jeneratör olabilir Paul bir jeneratörün hiçbir len () olmadığı gibi, ben "öğe, i numaralandırmak (l)" deyim ile giderdim. BTW, hangi tür tekrarlanabilir 1 ile çalışmaz? Jeneratörler ?!
ThomasH

Iterable = __iter __ () yöntemi döndüren yineleyici (next () yöntemi olan nesne)
Denis Otkidach


19

Kılavuzdan: s[i:j:k] slice of s from i to j with step k

li = range(100)
sub = li[0::10]

>>> sub
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

13
newlist = oldlist[::10]

Bu, listenin her 10. öğesini seçer.


4

Neden sadece range fonksiyonunun bir adım parametresini kullanmıyorsunuz?

l = range(0, 1000, 10)

Karşılaştırma için, makinemde:

H:\>python -m timeit -s "l = range(1000)" "l1 = [x for x in l if x % 10 == 0]"
10000 loops, best of 3: 90.8 usec per loop
H:\>python -m timeit -s "l = range(1000)" "l1 = l[0::10]"
1000000 loops, best of 3: 0.861 usec per loop
H:\>python -m timeit -s "l = range(0, 1000, 10)"
100000000 loops, best of 3: 0.0172 usec per loop

3
@SilentGhost: Bu doğru, ancak bu yeni başlayan bir soru olduğu için aralık işlevi gerçekten yapmak istedikleri şey olabilir, bu yüzden geçerli bir cevap olduğunu düşünüyorum. (Üst sınır 1000 değil 1001 olmalıdır)
Scott Griffiths

2
existing_list = range(0, 1001)
filtered_list = [i for i in existing_list if i % 10 == 0]

1
(0, 1001, 10) aralığı her 10 öğeyi zaten aldığında neden if deyimine sahipsiniz?
Autoplectic

4
Burada da aynı yorum, "daha büyük bir listede her n'th öğenin listesini döndürmek için Pythonic yolu" daha genel sorunu çözmez çözümünüzün örnek listesinin değerleri 0 ila 1000 ve sadece öğeleri çeker bağlıdır her 10'uncu öğe yerine 10'a bölünebilir bir değere sahip olan listeden.
Andre Miller

1
OP yazıyor: "Sıfırdan 1000'e kadar bir sayı listemiz var". Yani genel bir çözüme ihtiyacı yok.

1
O sadece bir örnek anlamına gelen 'Elimizdeki ..' yazıyor. Eğer sıfırın 1000 listesinden her 10. sayıyı gerçekten istiyorsa, cevap aralık (0,1001,10) veya benzer bir şey olacaktır.
Andre Miller

1

Aşağıda, liste içeriğini üyelik testinin bir parçası olarak kullanmayan "her 10'uncu madde" liste kavrayışının daha iyi bir uygulaması yer almaktadır:

>>> l = range(165)
>>> [ item for i,item in enumerate(l) if i%10==0 ]
[0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160]
>>> l = list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")
>>> [ item for i,item in enumerate(l) if i%10==0 ]
['A', 'K', 'U']

Ancak bu sadece liste dilimleme kullanmaktan çok daha yavaştır.


-9

Liste anlayışları tam olarak bunun için yapılır:

smaller_list = [x for x in range(100001) if x % 10 == 0]

Onlar hakkında daha fazla bilgiyi python resmi belgelerinde bulabilirsiniz: http://docs.python.org/tutorial/datastructures.html#list-comprehensions


Üst sınır 10000 değil 1000 olmalıdır. Çözümünüz, liste kavrama bağlantısı için aralık 999. + 1'de durduğundan 1000'in üst sınırını içermez.

19
Bu aslında her 10'uncu maddeyi değil, 10'a bölünebilir bir değeri olan her öğeyi çıkarır. Bu özel örnekte aynı şeydir, ancak olmayabilir.
Andre Miller
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.