2010-04-13 3 views
36

Python'da kod yazmak için çok fazla zaman harcıyor gibi hissediyorum, ama Pythonic kodu oluşturmaya yetecek kadar zamanım yok. Son zamanlarda, kolay ve idiomatik bir çözüm bulabileceğimi düşündüğüm komik bir problemle karşılaştım. Orijinali paraphraseing, bir listedeki her ardışık çifti toplamak gerekiyordu. Örneğin, [1,2,3,4,5,6] listesi verildiğinde, [(1,2),(3,4),(5,6)] hesaplamak istedim.Python "Her Diğer Eleman" Idiom

Çevrilmiş Java gibi görünen bir zamanda hızlı bir çözüm buldum. sorusunu tekrar bakıldığında, elimden gelen en boy bile olmadığı durumda son numarayı dışarı atarak yan etkisi yoktur

l = [1,2,3,4,5,6] 
[(l[2*x],l[2*x+1]) for x in range(len(l)/2)] 

oldu.

Eksik olduğum daha aptalca bir yaklaşım var mı, yoksa alacağım en iyisi mi?

+0

bu çözer’parçalar halinde bir liste üzerinde yineleme yolu?" http://stackoverflow.com/questions/434287/what-is-the-most-pythonic-way-to-iterate-over-a-list-in-chunks – jfs

cevap

78

Bu biraz daha düzgünce yapacağız:

>>> data = [1,2,3,4,5,6] 
>>> zip(data[0::2], data[1::2]) 
[(1, 2), (3, 4), (5, 6)] 

(eğer aralıklarının "adım" özelliği ile aşina değilseniz ama muhtemelen daha az okunabilir var).

Kodunuzda olduğu gibi, tek bir sayı değerinizin bulunduğu son değeri atar.

+3

'zip' işlevini seviyorum. –

+2

Tek sayılık senaryo senaryosunu işlemek için yukarıdakileri yapmadan önce 'data + = [None]' yapabilirsiniz. – badp

+1

'some_list + = [foo]' 'some_list.append (foo)' yazılmıştır. –

8

range() adımı özelliğini kullanma hakkında nasıl

[(l[n],l[n+1]) for n in range(0,len(l),2)] 
48

sık sık alıntılanan biridir:

zip(*[iter(l)] * 2) 
+8

awsome, ancak perl gibi okur - –

+0

Doğru, ama aynı zamanda şimdiye kadar sunulan en verimli çözüm olduğunu düşünüyorum. Ben test edeceğim, brb. – jemfinch

+1

Evet, herhangi bir bellek ayırma gerektirmediğinden ve giriş listesinde yalnızca bir yineleme gerektirmediğinden, RichieHindle çözümüne göre yaklaşık% 10 daha hızlıdır. – jemfinch

4

deneyin bu

def pairs(l, n): 
    return zip(*[l[i::n] for i in range(n)]) 

Yani,

pairs([1, 2, 3, 4], 2)

[(1, 2), (3, 4)] 
9

Genellikle bu benim koduna itertools belgelerinden grouper tarifi kopya verir.

def grouper(n, iterable, fillvalue=None): 
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx" 
    args = [iter(iterable)] * n 
    return izip_longest(fillvalue=fillvalue, *args) 
+1

+1, F Manual'den bahsetmek için :) – tzot

3

Listede sayıları deneme bile eğer unsurları kaybetmek istemiyorsanız bu:

>>> l = [1, 2, 3, 4, 5] 
>>> [(l[i], l[i+1] if i+1 < len(l) else None) for i in range(0, len(l), 2)] 
[(1, 2), (3, 4), (5, None)] 
4

doğru şey listelerini hesaplamak için ancak bir iterator- yazmak için değil muhtemelen > yineleyici işlevi. Bu daha genel - her yinelenen üzerinde çalışır ve bir listeye "dondurmak" istiyorsanız, "liste()" işlevini kullanabilirsiniz. belki ileride revizyon -

def groupElements(iterable, n): 
    # For your case, you can hardcode n=2, but I wanted the general case here. 
    # Also, you do not specify what to do if the 
    # length of the list is not divisible by 2 
    # I chose here to drop such elements 
    source = iter(iterable) 
    while True: 
     l = [] 
     for i in range(n): 
      l.append(source.next()) 
     yield tuple(l) 

Ben itertools modülü zaten bunun için bir işleve sahip değildir şaşırdım. O zamana kadar, yukarıdaki sürümü kullanmaktan çekinmeyin :)

+0

Performansa benzeyen nedir? – LondonRob

4

toolz itertools'ta gözden kaçan birçok fonksiyonel programlama ile iyi inşa edilmiş bir kütüphanedir.partition (pad için bir seçenek tek uzunlukta listeleri için son kayıt) pythonic "En nedir‘ile ilgili

>>> list(toolz.partition(2, [1,2,3,4,5,6])) 
[(1, 2), (3, 4), (5, 6)]