42

シーケンスのシーケンス (おそらくタプルのリスト) がある場合は、 itertools.chain() を使用してフラット化できます。しかし、理解として書きたいと思うこともあります。私はそれを行う方法を理解できません。これは非常に解釈されたケースです:

シーケンス内のすべてのペアの要素を交換したいとしましょう。ここでは文字列をシーケンスとして使用します。

>>> from itertools import chain
>>> seq = '012345'
>>> swapped_pairs = zip(seq[1::2], seq[::2])
>>> swapped_pairs
[('1', '0'), ('3', '2'), ('5', '4')]
>>> "".join(chain(*swapped_pairs))
'103254'

シーケンスの偶数スライスと奇数スライスで zip を使用してペアを交換します。しかし、フラット化する必要があるタプルのリストができあがります。だから私は chain() を使います。代わりに理解して表現する方法はありますか?

ペアの要素を交換するという基本的な問題に対する独自の解決策を投稿したい場合は、先に進んでください。何か新しいことを教えてくれるものは何でも賛成票を投じます。ただし、回答が「いいえ、できません」であっても、私の質問を対象とした回答のみを承認済みとしてマークします。

4

4 に答える 4

32

了解で?良い...

>>> seq = '012345'
>>> swapped_pairs = zip(seq[1::2], seq[::2])
>>> ''.join(item for pair in swapped_pairs for item in pair)
'103254'
于 2009-01-19T10:58:49.290 に答える
16

私が見つけた最も速い方法は、空の配列から始めてそれを拡張することです:

In [1]: a = [['abc', 'def'], ['ghi'],['xzy']]

In [2]: result = []

In [3]: extend = result.extend

In [4]: for l in a:
   ...:     extend(l)
   ...: 

In [5]: result
Out[5]: ['abc', 'def', 'ghi', 'xzy']

これは、Alex Martelli の試みの例の 2 倍以上高速です: Making a flat list out of list of list in Python

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in l for item in sublist]'
10000 loops, best of 3: 86.3 usec per loop

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]*99'  'b = []' 'extend = b.extend' 'for sub in l:' '    extend(sub)'
10000 loops, best of 3: 36.6 usec per loop

これを思いついたのは、バックグラウンドでextendがリストに適切な量のメモリを割り当て、おそらくいくつかの低レベルコードを使用してアイテムを移動するという予感があったためです。これが本当かどうかはわかりませんが、誰が気にしても、それはより高速です。

ちなみに、これは線形の高速化のみです。

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]'  'b = []' 'extend = b.extend' 'for sub in l:' '    extend(sub)'
1000000 loops, best of 3: 0.844 usec per loop

$ python -mtimeit -s'l=[[1,2,3],[4,5,6], [7], [8,9]]' '[item for sublist in l for item in sublist]'
1000000 loops, best of 3: 1.56 usec per loop

を使用することもできますがmap(results.extend, a)、これは独自の Nones リストを作成しているため遅くなります。

また、関数型プログラミングを使用しない利点もいくつかあります。すなわち

  • 空のリストを作成する代わりに、既存のリストを拡張できます。
  • 数分後、数日後、さらには数か月後でも、一目でコードを理解できます。

ところで、おそらくリスト内包表記は避けるのが最善でしょう。小さなリスト内包表記はそれほど悪くはありませんが、一般的に、リスト内包表記は入​​力の手間をあまり省きませんが、多くの場合、理解するのが難しく、変更やリファクタリングが非常に困難です (3 レベルのリスト内包表記を見たことがありますか?)。Google のコーディング ガイドラインでは、単純な場合を除き、それらを使用しないことを推奨しています。私の意見では、それらは「使い捨て」コード、つまり作成者が可読性を気にしないコード、または将来のメンテナンスを必要としないことが知られているコードでのみ有用であるというものです。

同じことを書く次の 2 つの方法を比較します。

result = [item for sublist in l for item in sublist]

これとともに:

result = []
for sublist in l:
    for item in sublist:
        result.append(item)

YMMV ですが、最初の 1 つで足が止まり、考えなければなりませんでした。2 番目の例では、入れ子がインデントから明らかになっています。

于 2011-03-16T18:44:22.503 に答える
3

reduce を使用して目標を達成できます。

In [6]: import operator
In [7]: a = [(1, 2), (2,3), (4,5)]
In [8]: reduce(operator.add, a, ())
Out[8]: (1, 2, 2, 3, 4, 5)

元のリストの要素は連結されるタプルであるため、これはリストではなくタプルを返します。しかし、そこから簡単にリストを作成でき、join メソッドはタプルも受け入れます。

ちなみに、リスト内包表記はそのための適切なツールではありません。基本的に、リスト内包表記は、このリストの要素がどのように見えるべきかを記述することによって、新しいリストを構築します。要素のリストを 1 つの値だけに減らしたい。

于 2009-01-19T10:54:08.083 に答える
1
>>> a = [(1, 2), (3, 4), (5, 6)]
>>> reduce(tuple.__add__, a)
>>> (1, 2, 3, 4, 5, 6)

または、内部シーケンスのタイプにとらわれないようにするには (それらがすべて同じである限り):

>>> reduce(a[0].__class__.__add__, a)
于 2009-01-19T14:34:44.487 に答える