37
[[1, '34', '44'], [1, '40', '30', '41'], [1, '41', '40', '42'], [1, '42', '41', '43'], [1, '43', '42', '44'], [1, '44', '34', '43']]

リストのリストがあります。私の目的は、1 つのサブリストに他のサブリストと共通点があるかどうかを確認することです (比較する最初のインデックス オブジェクトを除く)。共通点がある場合は、それらのサブリストを統合します。

たとえば、この例の場合、最終的な答えは次のようになります。

[[1, '34, '44', '40' '30', '41', '42', '43']]

サブリストをセットに変換してから、union() および Intersection() 操作を使用する必要があることは理解できます。しかし、私がこだわっているのは、各セット/サブリストを比較する方法です。リストの内容が変更されてエラーが発生するため、リストに対してループを実行して各サブリストを 1 つずつ比較することはできません。

私が知りたいのは、すべてのサブリスト(セットに変換された)を比較し、それらの結合を取得する効率的な方法はありますか?

4

7 に答える 7

63

itertoolsモジュールは、この問題を簡単に解決します:

>>> from itertools import chain
>>> list(set(chain.from_iterable(d)))
[1, '41', '42', '43', '40', '34', '30', '44']

これを行う別の方法は、リストを unpack ()の個別の引数にアンパックすることです。

>>> list(set().union(*d))
[1, '41', '42', '43', '40', '34', '30', '44']

後者の方法では、すべての重複が排除され、最初に入力をセットに変換する必要がありません。また、インポートは必要ありません。

于 2015-06-11T07:40:05.800 に答える
39

アンパック演算子*の使用:

>> list(set().union(*a))
[1, '44', '30', '42', '43', '40', '41', '34']

(コメントをくれた Raymond Hettinger と ShadowRanger に感謝します!)

(ご了承ください

set.union(*tup)

に解凍します

set.union(tup[0], tup[1], ... tup[n - 1])

)

于 2015-06-11T07:12:11.500 に答える
1
>>> big = [[1, '34', '44'], [1, '40', '30', '41'], [1, '41', '40', '42'], [1, '42', '41', '43'], [1, '43', '42', '44'], [1, '44', '34', '43']]
>>> set(reduce ( lambda l,a : l + a, big))
set([1, '44', '30', '42', '43', '40', '41', '34'])

そして、最終結果としてリストのリストが本当に必要な場合

>>>>[list(set(reduce ( lambda l,a : l + a, big)))]
[[1, '44', '30', '42', '43', '40', '41', '34']]

また、リストの追加のためにラムダ関数を再コーディングしたくない場合は、次のようにします。

>>>>[list(set(reduce ( list.__add__, big)))]
[[1, '44', '30', '42', '43', '40', '41', '34']]

編集: list.__add__ の代わりに itertools.chain を使用することについてのあなたの推奨の後、元のポスターで使用された元の変数を使用して、両方の timeit を実行しました。

timeit の時間は list.__add__ で約 2.8 秒、itertools.chain で約 3.5 秒のようです。

私はこのページをチェックしましたが、そうです、 itertools.chain には from_iterable メソッドが含まれており、パフォーマンスが大幅に向上します。以下の list.__add__、itertools.chain、および itertools.chain.from_iterable を参照してください。

>>> timeit.timeit("[list(set(reduce ( list.__add__, big)))]", setup="big = [ [10,20,30,40] for ele in range(10000)]", number=30)
16.051744650801993
>>> timeit.timeit("[list(set(reduce ( itertools.chain, big)))]", setup="big = [ [10,20,30,40] for ele in range(10000)]", number=30)
54.721315866467194
>>> timeit.timeit("list(set(itertools.chain.from_iterable(big)))", setup="big = [ [10,20,30,40] for ele in range(10000)]", number=30)
0.040056066849501804

アドバイスありがとうございます:)

于 2015-06-11T07:19:38.233 に答える
1
In [20]: s
Out[20]: 
[[1, '34', '44'],
 [1, '40', '30', '41'],
 [1, '41', '40', '42'],
 [1, '42', '41', '43'],
 [1, '43', '42', '44'],
 [1, '44', '34', '43']]
In [31]: list({x for _list in s for x in _list})
Out[31]: [1, '44', '30', '42', '43', '40', '41', '34']

アップデート:

コメントありがとうございます

于 2015-06-11T07:13:01.643 に答える
1

itertools を使用して、このアクションを実行できます。リストに変数名 A があると仮定しましょう

import itertools

single_list_with_all_values = list(itertools.chain(*A))
single_list_with_all_values.sort()

print set(single_list_with_all_values)
于 2015-06-11T07:14:43.473 に答える
0

Python 2 のみでテスト済み: 個人的にはreduce、次のような単純な条件付き関数と組み合わせた の読みやすさが気に入っています。

# PYTHON 2 ONLY!
somelists = [[1, '41', '40', '42'], [1, '42', '41', '43'], [1, '43', '42', '44'], [1, '44', '34', '43']] # your original lists
somesets = map(set,somelists) #your lists as sets

def condition(s1,s2): # condition to apply recursively to the sets
    if s1.intersection(s2):
        return s1.union(s2)
reduce( condition,somesets)
#{1, '30', '34', '40', '41', '42', '43', '44'}

もちろん、必要に応じて、この結果を 2 次元リストにキャストできますlist([reduce(...

chain.fromiterableこれは、答えよりも3倍遅いことに注意してください。

于 2015-07-30T22:33:40.193 に答える