web-dev-qa-db-ja.com

Python "その他すべての要素"イディオム

Pythonでコードを書くのに多くの時間を費やしているように感じますが、Pythonicコードの作成には十分な時間ではありません。最近、私は簡単で慣用的な解決策があるかもしれないと思った面白い小さな問題に遭遇しました。オリジナルを言い換えると、リスト内のすべての順次ペアを収集する必要がありました。たとえば、_[1,2,3,4,5,6]_というリストがある場合、[(1,2),(3,4),(5,6)]を計算したいと思いました。

当時、私は翻訳されたJavaのように見える簡単な解決策を思いつきました。質問を振り返って、私ができる最善のことは

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

これには、長さが均一でない場合に最後の数値を投げるという副作用があります。

私が見逃しているもっと慣用的なアプローチはありますか、それともこれが私が得る最高のものですか?

38
Matt Luongo

これはもう少しきれいにそれをします:

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

(ただし、範囲の「ストライド」機能に慣れていない場合は、おそらく読みにくくなります)。

コードと同様に、奇数の値がある最後の値を破棄します。

81
RichieHindle

よく引用されるのは:

Zip(*[iter(l)] * 2)

私はiterソリューションのより読みやすいバージョンを好みます:

it = iter(l)
list(Zip(it, it))
# [(1, 2), (3, 4), (5, 6)]

私は通常、grouperレシピを itertools ドキュメントから私のコードにコピーします。

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

range()のステップ機能を使用するのはどうですか?

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

正しいことは、おそらくリストを計算することではなく、反復子->反復子関数を書くことです。これはより一般的です-すべての反復可能オブジェクトで機能し、リストに「フリーズ」したい場合は、「list()」関数を使用できます。

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)

Itertoolsモジュールがそのための機能をまだ持っていないことに驚いています-おそらく将来のリビジョンです。それまでは、上記のバージョンを自由に使用してください:)

4
moshez

これを試して

_def pairs(l, n):
    return Zip(*[l[i::n] for i in range(n)])
_

そう、

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

_[(1, 2), (3, 4)]
_
4
prasanna

toolz は、itertoolsで見過ごされている多くの関数型プログラミングの優れた機能を備えた、よく構築されたライブラリです。 partition これを解決します(奇数長のリストの最後のエントリを埋め込むオプションを使用)

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

リスト内の要素の数がこれでなくても要素を失いたくない場合:

>>> 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)]
3
Kamil Szot