37

問題は簡単です。リストの各要素と次の要素をペアで繰り返します(最後の要素を最初の要素でラップします)。

私はそれを行うための2つの非Python的な方法について考えました:

def pairs(lst):
    n = len(lst)
    for i in range(n):
        yield lst[i],lst[(i+1)%n]

と:

def pairs(lst):
    return zip(lst,lst[1:]+[lst[:1]])

期待される出力:

>>> for i in pairs(range(10)):
    print i

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)
(6, 7)
(7, 8)
(8, 9)
(9, 0)
>>> 

これを行うためのよりPython的な方法についての提案はありますか?多分私が聞いたことがない事前定義された関数がそこにありますか?

また、より一般的なn-fold(ペアの代わりにトリプレット、カルテットなどを使用)バージョンも興味深いかもしれません。

4

13 に答える 13

30
def pairs(lst):
    i = iter(lst)
    first = prev = item = i.next()
    for item in i:
        yield prev, item
        prev = item
    yield item, first

空でない任意のシーケンスで機能し、インデックス作成は不要です。

于 2009-08-10T21:57:01.947 に答える
9

私はタプルの一般的なバージョンを自分でコーディングしました。最初のものはエレガントなシンプルさで気に入っています。見れば見るほど、Pythonic に感じられます...結局のところ、zip を使用した 1 つのライナーよりも Pythonic とは何ですか? 、アスタリスク引数の展開、リスト内包表記、リストのスライス、リストの連結、および「範囲」?

def ntuples(lst, n):
    return zip(*[lst[i:]+lst[:i] for i in range(n)])

itertools バージョンは、大きなリストでも十分に効率的である必要があります...

from itertools import *
def ntuples(lst, n):
    return izip(*[chain(islice(lst,i,None), islice(lst,None,i)) for i in range(n)])

そして、インデックス付けできないシーケンスのバージョン:

from itertools import *
def ntuples(seq, n):
    iseq = iter(seq)
    curr = head = tuple(islice(iseq, n))
    for x in chain(iseq, head):
        yield curr
        curr = curr[1:] + (x,)

とにかく、皆さんの提案に感謝します!:-)

于 2009-08-10T22:37:22.583 に答える
6

いつものように、私はティーが好きです:

from itertools import tee, izip, chain

def pairs(iterable):
    a, b = tee(iterable)
    return izip(a, chain(b, [next(b)]))
于 2012-03-27T07:32:21.293 に答える
5

これで十分かもしれません:

def pairs(lst):
    for i in range(1, len(lst)):
        yield lst[i-1], lst[i]
    yield lst[-1], lst[0]

>>> a = list(range(5))
>>> for a1, a2 in pairs(a):
...     print a1, a2
...
0 1
1 2
2 3
3 4
4 0

この種のものが好きなら、wordaligned.orgの python の記事を見てください。著者は、Python のジェネレーターが特に好きです。

于 2009-08-10T22:00:18.883 に答える
2

私はこのようにします(主にこれを読むことができるからです):

class Pairs(object):
    def __init__(self, start):
        self.i = start
    def next(self):
        p, p1 = self.i, self.i + 1
        self.i = p1
        return p, p1
    def __iter__(self):
        return self

if __name__ == "__main__":
    x = Pairs(0)
    y = 1
    while y < 20:
        print x.next()
        y += 1

与えます:

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)
(6, 7)
(7, 8)
(8, 9)
于 2009-08-10T23:08:30.370 に答える
1
[(i,(i+1)%len(range(10))) for i in range(10)]

range(10) を必要なリストに置き換えます。

一般に、「循環インデックス」は Python では非常に簡単です。ちょうど使用:

a[i%len(a)] 
于 2011-06-05T10:05:32.790 に答える
0

一般的なケースの解決に関する質問に答えるには:

import itertools

def pair(series, n):
    s = list(itertools.tee(series, n))
    try:
        [ s[i].next() for i in range(1, n) for j in range(i)]
    except StopIteration:
        pass
    while True:
        result = []
        try:
            for j, ss in enumerate(s):
                result.append(ss.next())
        except StopIteration:
            if j == 0:
                break
            else:
                s[j] = iter(series)
                for ss in s[j:]:
                    result.append(ss.next())
        yield result

出力は次のようになります。

>>> for a in pair(range(10), 2):
...     print a
...
[0, 1]
[1, 2]
[2, 3]
[3, 4]
[4, 5]
[5, 6]
[6, 7]
[7, 8]
[8, 9]
[9, 0]
>>> for a in pair(range(10), 3):
...     print a
...
[0, 1, 2]
[1, 2, 3]
[2, 3, 4]
[3, 4, 5]
[4, 5, 6]
[5, 6, 7]
[6, 7, 8]
[7, 8, 9]
[8, 9, 0]
[9, 0, 1]
于 2009-08-10T22:27:19.813 に答える
0
def pairs(ex_list):
    for i, v in enumerate(ex_list):
        if i < len(list) - 1:
            print v, ex_list[i+1]
        else:
            print v, ex_list[0]

Enumerate は、インデックス番号と値のタプルを返します。list の値と次の要素を出力しますex_list[i+1]。ifi < len(list) - 1は、v がリストの最後のメンバーでない場合を意味します。そうであれば: v と list の最初の要素を出力しますprint v, ex_list[0]

編集:

リストを返すようにすることができます。出力されたタプルをリストに追加して返すだけです。

def pairs(ex_list):
    result = []
    for i, v in enumerate(ex_list):
        if i < len(list) - 1:
            result.append((v, ex_list[i+1]))
        else:
            result.append((v, ex_list[0]))
    return result
于 2013-05-15T14:13:47.633 に答える
0

これは良くも悪くも無限に循環しますが、アルゴリズム的には非常に明確です。

from itertools import tee, cycle

def nextn(iterable,n=2):
    ''' generator that yields a tuple of the next n items in iterable.
    This generator cycles infinitely '''
    cycled = cycle(iterable)
    gens = tee(cycled,n)

    # advance the iterators, this is O(n^2)
    for (ii,g) in zip(xrange(n),gens):
        for jj in xrange(ii):
            gens[ii].next()

    while True:
        yield tuple([x.next() for x in gens])


def test():
    data = ((range(10),2),
        (range(5),3),
        (list("abcdef"),4),)
    for (iterable, n) in data:
        gen = nextn(iterable,n)
        for j in range(len(iterable)+n):
            print gen.next()            


test()

与えます:

(0, 1)
(1, 2)
(2, 3)
(3, 4)
(4, 5)
(5, 6)
(6, 7)
(7, 8)
(8, 9)
(9, 0)
(0, 1)
(1, 2)
(0, 1, 2)
(1, 2, 3)
(2, 3, 4)
(3, 4, 0)
(4, 0, 1)
(0, 1, 2)
(1, 2, 3)
(2, 3, 4)
('a', 'b', 'c', 'd')
('b', 'c', 'd', 'e')
('c', 'd', 'e', 'f')
('d', 'e', 'f', 'a')
('e', 'f', 'a', 'b')
('f', 'a', 'b', 'c')
('a', 'b', 'c', 'd')
('b', 'c', 'd', 'e')
('c', 'd', 'e', 'f')
('d', 'e', 'f', 'a')
于 2009-08-11T00:42:37.237 に答える
0

Fortran の zip * range ソリューションのさらに短いバージョン (今回はラムダを使用):

group = lambda t, n: zip(*[t[i::n] for i in range(n)])

group([1, 2, 3, 3], 2)

与えます:

[(1, 2), (3, 4)]
于 2010-02-09T19:05:51.080 に答える
0

オプションの開始インデックスをサポートするバージョンを次に示します (たとえば、最初のペアとして (4, 0) を返すには、start = -1 を使用します。

import itertools

def iterrot(lst, start = 0):

    if start == 0:
        i = iter(lst)
    elif start > 0:
        i1 = itertools.islice(lst, start, None)
        i2 = itertools.islice(lst, None, start)
        i = itertools.chain(i1, i2)
    else:
        # islice doesn't support negative slice indices so...
        lenl = len(lst)
        i1 = itertools.islice(lst, lenl + start, None)
        i2 = itertools.islice(lst, None, lenl + start)
        i = itertools.chain(i1, i2)
    return i


def iterpairs(lst, start = 0):

    i = iterrot(lst, start)     

    first = prev = i.next()
    for item in i:
        yield prev, item
        prev = item
    yield prev, first


def itertrios(lst, start = 0):

    i = iterrot(lst, start)     

    first = prevprev = i.next()
    second = prev = i.next()
    for item in i:
        yield prevprev, prev, item
        prevprev, prev = prev, item

    yield prevprev, prev, first
    yield prev, first, second
于 2011-04-10T18:44:48.637 に答える
-1
i=(range(10))

for x in len(i):
    print i[:2]
    i=i[1:]+[i[1]]

これ以上のpythonicは不可能です

于 2011-01-04T01:59:53.710 に答える