リストのリストをマージする6つの方法

ここで私たちのオフィスでは、会話が最も「美しい」ものとして入力され、Pythonのリストのリストをすばやく接着しました。 ほんとに?



そのような一見些細な問題でさえ、速度と表現力が大きく異なるいくつかの方法で解決できます。



オプション1

リストアイテムはループスルーでき、最後にアイテムを追加できることは誰もが知っています。 これは、最初の解決策につながります。

def listmerge1 ( lstlst ) :

すべて = [ ]

lstlstのlstの場合:

lstのelの場合:

すべて 。 追加 ( el )

すべて 返す


それだけでなく、この機能は6行にも及ぶだけでなく、効果もありません。

速度と美しさ(「pythonic way」)の両方の意味で改善してみましょう。



オプション2

ここでは、Pythonには文字列に演算子「+」があり、次のようになることを思い出します。

def listmerge2 ( lstlst ) :

すべて = [ ]

lstlstのlstの場合:

all = all + lst

すべて 返す


これは最も遅い実装です。 パンクは、この形式では、各ステップの「+」演算子が新しいリストオブジェクトを作成し、それが次のステップなどでスローされることです。



オプション3

簡単に修正できるため、「+」を新しいリストを作成せずに古いリストに追加するフォームに置き換える必要があります。 これは "+ ="演算子ですが、明示的に "extend"メソッドを記述することを好みます。



したがって、最速のオプションではなく最速のオプションを選択しました。

def listmerge3 ( lstlst ) :

すべて = [ ]

lstlstのlstの場合:

すべて 。 拡張 ( lst )

すべて 返す


これらは1つの式で構成されているため、ラムダ式を使用して後続のすべての決定を記述します。 引数の名前はllに減ります。これは、1行のコードでは読みやすさが低下しないためです。

#匿名関数経由

listmerge = lambda ll:シンプルステートメント

#同等

def listmerge ( ll ) :

シンプルステートメントを返す


オプション4

リストを操作するための組み込み関数を使用して、関数プログラミングのスタイルでオプション2を書き換えることができます。

listmerge4a = lambda ll: reduce ( lambda a、b:a + b、ll、 [ ] )

listmerge4b = lambda ll: sum ( ll、 [ ] )


彼は少し速くなっていますが、それでも彼の反復的な親sameと同じ理由でブレーキをかけています。 ここで、「ラムダa、b:a + b」は、単に合計を返す2つの引数の匿名関数です。 オプションBは、要素の合計を計算するための便利なPythonに組み込まれた単なるショートカットです。 このオプションは最短です。



個人的には、最短(速度)も最速(美)も私に適していません。 妥協点を見つけよう。



オプション5

リスト式の使用:

listmerge5 = lambda ll: [ lstの場合はel 、 lstの場合は ll ]


前のものよりもそれほど長くはありませんが、根本的に高速です。 このオプションは間違いなく美しいですが、ネストされたリスト式は一見すると必ずしも明確ではありません。



オプション6

しかし、最速のオプションを機能的なスタイルで書き直そうとするとどうなりますか? 簡単:

listmerge6 = lambda s: reduce ( lambda d、el:d。extend ( el ) または d、s、 [ ] )


extendメソッドはNoneを返すため、 「 d.extend(el)またはd 」に「 または 」演算子を追加する必要があります。 速度に関しては、実際には最速の方法3より劣っていません(速度の違いは文字通り数パーセントであり、私の意見では重要ではありません)。



私の意見では、「 編集上の選択 」にはオプション番号6が与えられるべきです



Pythonの小さなコードの速度を測定するために、 timeitライブラリがあります。 以下に、コードテストオプション3、5、6(最速かつ最も美しい)の例を示します。

インポート timeit



オプション= {

「削減」 :

'listmerge = lambda s:reduce(lambda d、el:d.extend(el)or d、s、[])' 、

「反復」 :

「」「

def listmerge(lstlst):

すべて= []

lstlstのlstの場合:

all.extend(lst)

すべて返す

"" " 、

「理解」 :

'listmerge = lambda ll:[x in lst in ll for x for lst]' 、

}



initstr = 'lstlst = [range(i)for i in range(1000)] \ n gc.enable()'



def テスト ( variant、initstr、n = 100 ) :

print "テストの繰り返しn =" 、n、 "回\ n INITSTR:" 、initstr、 " \ n \ n "

バリアントのk、vの場合。 iteritems ( ) :

k、 「-」 、 timeitを出力します。 タイマー ( 「listmerge(lstlst)」 、initstr + 「 \ n 」 + v ) 。 timeit ( n )

印刷する



テスト ( options、initstr、 100 )


タイムテストを開始する例。 反復バリアントと機能バリアントの速度の差はごくわずかであることがわかります。 リスト式のオプションは著しく遅くなります(ここではエラーを書き消すことはできません)が、リストのサイズは非常に大きく、スピードが重要ではないアプリケーションの場合は、生存権もあります。

Test repeats n = 100 times

INITSTR: lstlst=[range(i) for i in range(1000)]

gc.enable()



Iterate - 1.56133103371

Reduce - 1.57647109032

Comprehension - 7.5749669075









ホーム

ネストされたリストを線形リストに配置するより複雑なタスクを解決/議論することを提案します。

例:

#ソースリスト:

[ 7 、 [ [ [ [ 2 ] ] ] 、 [ [ [ ] ] 、 [ 4 ] ] 、 [ 4、5 、 [ 6、7 ] ] ] 、 8 ]

#結果:

[ 7、2、4、4、5、6、7、8 ]




UPD:返信habrahabr.ru/blogs/python/63539/#comment_1764419



UPD2:

オプション6B (LiveJournalの匿名コメンテーターから)

輸入 業者

listmerge6b = lambda s: reduce ( operator。iadd 、s、 [ ] )



All Articles