2つのネストされたリストの共通部分を見つけますか?


468

2つのフラットリストの共通部分を取得する方法を知っています。

b1 = [1,2,3,4,5,9,11,15]
b2 = [4,5,6,7,8]
b3 = [val for val in b1 if val in b2]

または

def intersect(a, b):
    return list(set(a) & set(b))

print intersect(b1, b2)

しかし、ネストされたリストの共通部分を見つける必要がある場合、問題が発生します。

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

最後に私は受け取りたいです:

c3 = [[13,32],[7,13,28],[1,6]]

これで私に手を貸してくれませんか?

関連した


c1がc2を交差するための交差点は何ですか?c1がc2にあるかどうかを単純に検索しますか?または、c2のどこかに現れるc1のすべての要素を検索しますか?
ブライアンR.ボンディ

これを読んで、通訳で遊んでください。
Pithikos、2015年

回答:


177

お望みならば:

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
c3 = [[13, 32], [7, 13, 28], [1,6]]

次に、Python 2のソリューションを示します。

c3 = [filter(lambda x: x in c1, sublist) for sublist in c2]

Python 3 filterでは、の代わりにイテラブルを返すlistため、filter呼び出しをlist()次のようにラップする必要があります。

c3 = [list(filter(lambda x: x in c1, sublist)) for sublist in c2]

説明:

フィルターパーツは、各サブリストのアイテムを取得し、ソースリストc1にあるかどうかを確認します。リスト内包表記は、c2のサブリストごとに実行されます。


35
filter(set(c1).__contains__, sublist)効率よくお使いいただけます。ところで、このソリューションの利点は、filter()文字列とタプルの型を保持することです。
jfs 2009年

3
私はこの方法が好きですが、結果のリストで ''が空白になります
Jonathan Ong

私はここにPython 3互換を追加しました。これをPython 3の質問の
複製の複製

9
これは、ネストされた内包とのより良いIMO読み:c3 = [[x for x in sublist if x in c1] for sublist in c2]
エリック・

894

交差を定義する必要はありません。すでにファーストクラスのセットです。

>>> b1 = [1,2,3,4,5,9,11,15]
>>> b2 = [4,5,6,7,8]
>>> set(b1).intersection(b2)
set([4, 5])

3
セットへの変換のため、これはラムダより遅くなりますか?
Ciro Santilli郝海东冠状病六四事件法轮功

32
@ S.Lott、何か問題がありset(b1) & set(b2)ますか?演算子を使用するIMOそのクリーナー。
gwg 2015

4
さらに、使用setすると、コードが桁違いに速くなります。次に、benchmark®の例を示します。gist.github.com
andersonvom

5
結果を並べ替える必要がない場合にのみ機能します。
Borbag​​ 2017

7
だから...この答えは質問に答えるものではありませんよね?これは、ネストされたリストで機能するようになったためです。
Mayou36 '06 / 09/17

60

2つのリストの共通部分を探しているだけの人のために、Askerは2つのメソッドを提供しました。

b1 = [1,2,3,4,5,9,11,15]
b2 = [4,5,6,7,8]
b3 = [val for val in b1 if val in b2]

そして

def intersect(a, b):
     return list(set(a) & set(b))

print intersect(b1, b2)

ただし、リスト/セット間の変換は3つではなく1つで済むため、より効率的なハイブリッド方式があります。

b1 = [1,2,3,4,5]
b2 = [3,4,5,6]
s2 = set(b2)
b3 = [val for val in b1 if val in s2]

これはO(n)で実行されますが、リスト内包を含む彼の元のメソッドはO(n ^ 2)で実行されます


"if val in s2"はO(N)で実行されるため、提案されるコードスニペットの複雑さもO(n ^ 2)です
Romeno

8
「val in s2」の平均的なケースはwiki.python.org/moin/TimeComplexity#setによるとO(1)です -したがって、n回の操作で予想される時間はO(n)です(最悪の場合の時間はO( n)またはO(n ^ 2)は、この平均的なケースが償却時間を表すかどうかによって異なりますが、実際にはそれほど重要ではありません)。
D Coetzee 2013年

2
ランタイムがO(N)であるのは、それが償却されるからではなく、セットメンバーシップが平均O(1)であるため(たとえば、ハッシュテーブルを使用する場合)、たとえば、償却時間が保証されるため、それは大きな違いです。
miroB

28

機能的アプローチ:

input_list = [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

result = reduce(set.intersection, map(set, input_list))

そしてそれは1+リストのより一般的なケースに適用できます


空の入力リストを許可するには:set(*input_list[:1]).intersection(*input_list[1:])。イテレータ版(it = iter(input_list)): reduce(set.intersection, it, set(next(it, [])))。どちらのバージョンでも、すべての入力リストを変換して設定する必要はありません。後者はよりメモリ効率が良いです。
jfs

from functools import reducePython 3で使用するために使用します。あるいは、明示的なforループを使用することをお勧めします。
TrigonaMinima

27

ピュアリスト読解版

>>> c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
>>> c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
>>> c1set = frozenset(c1)

フラット化バリアント:

>>> [n for lst in c2 for n in lst if n in c1set]
[13, 32, 7, 13, 28, 1, 6]

ネストされたバリアント:

>>> [[n for n in lst if n in c1set] for lst in c2]
[[13, 32], [7, 13, 28], [1, 6]]

20

&演算子は、2つのセットの共通部分を取ります。

{1, 2, 3} & {2, 3, 4}
Out[1]: {2, 3}

いいですが、このトピックはリスト用です!
Rafa0809

3
2つのリストの共通部分の結果はセットなので、この答えは完全に有効です。
shrewmouse 2017年

リストには重複する値を含めることができますが、セットには含まれません。
diewland 2018年

13

2つのリストの共通部分を取るpythonの方法は次のとおりです。

[x for x in list1 if x in list2]

2
この質問は、ネストされたリストについてです。あなたの答えは質問には答えません。
トーマス

8

このコード(http://kogs-www.informatik.uni-hamburg.de/~meine/python_tricksから取得)を使用してフラット化する必要があります。コードはテストされていませんが、動作することはほぼ間違いありません。


def flatten(x):
    """flatten(sequence) -> list

    Returns a single, flat list which contains all elements retrieved
    from the sequence and all recursively contained sub-sequences
    (iterables).

    Examples:
    >>> [1, 2, [3,4], (5,6)]
    [1, 2, [3, 4], (5, 6)]
    >>> flatten([[[1,2,3], (42,None)], [4,5], [6], 7, MyVector(8,9,10)])
    [1, 2, 3, 42, None, 4, 5, 6, 7, 8, 9, 10]"""

    result = []
    for el in x:
        #if isinstance(el, (list, tuple)):
        if hasattr(el, "__iter__") and not isinstance(el, basestring):
            result.extend(flatten(el))
        else:
            result.append(el)
    return result

リストをフラット化した後、通常の方法で交差を実行します。


c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

def intersect(a, b):
     return list(set(a) & set(b))

print intersect(flatten(c1), flatten(c2))

2
これはコードGeoをフラット化するのに最適ですが、質問の答えにはなりません。質問者は特に[[13,32]、[7,13,28]、[1,6]]という形式の結果を期待します。
Rob Young

8

以来intersect定義された、基本的なリスト内包表記は十分です。

>>> c3 = [intersect(c1, i) for i in c2]
>>> c3
[[32, 13], [28, 13, 7], [1, 6]]

S. Lottの発言とTM。の関連発言による改善:

>>> c3 = [list(set(c1).intersection(i)) for i in c2]
>>> c3
[[32, 13], [28, 13, 7], [1, 6]]

5

与えられた:

> c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]

> c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

次のコードはうまく機能し、set演算を使用するとより簡潔になる可能性があります。

> c3 = [list(set(f)&set(c1)) for f in c2] 

それは得ました:

> [[32, 13], [28, 13, 7], [1, 6]]

注文が必要な場合:

> c3 = [sorted(list(set(f)&set(c1))) for f in c2] 

私たちは得ました:

> [[13, 32], [7, 13, 28], [1, 6]]

ちなみに、より多くのpythonスタイルの場合、これも問題ありません。

> c3 = [ [i for i in set(f) if i in c1] for f in c2]

3

私があなたの質問に答えるのが遅いかどうかわかりません。あなたの質問を読んだ後、リストとネストされたリストの両方で機能するintersect()関数を思いつきました。この関数を定義するために再帰を使用しました。非常に直感的です。それがあなたが探しているものであることを願っています:

def intersect(a, b):
    result=[]
    for i in b:
        if isinstance(i,list):
            result.append(intersect(a,i))
        else:
            if i in a:
                 result.append(i)
    return result

例:

>>> c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
>>> c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
>>> print intersect(c1,c2)
[[13, 32], [7, 13, 28], [1, 6]]

>>> b1 = [1,2,3,4,5,9,11,15]
>>> b2 = [4,5,6,7,8]
>>> print intersect(b1,b2)
[4, 5]

2

[1,2]交差することを検討し[1, [2]]ますか?つまり、気になるのは数字だけですか、それともリスト構造ですか?

数値のみの場合は、リストを「平坦化」する方法を調べ、set()メソッドを使用します。


リストの構造は変更しないでおきたい。
elfuego1 2009年

1

私はそれを行う方法も探していましたが、最終的には次のようになりました。

def compareLists(a,b):
    removed = [x for x in a if x not in b]
    added = [x for x in b if x not in a]
    overlap = [x for x in a if x in b]
    return [removed,added,overlap]

set.intersectionを使用しない場合、これらの単純な1ライナーは私が行うことでもあります。
slaughter98

0
c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]

c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

c3 = [list(set(c2[i]).intersection(set(c1))) for i in xrange(len(c2))]

c3
->[[32, 13], [28, 13, 7], [1, 6]]

0

これにはsetメソッドを使用できます。

c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]

   result = [] 
   for li in c2:
       res = set(li) & set(c1)
       result.append(list(res))

   print result

0

要素のカーディナリティを正しく考慮した交差を定義するには、次を使用しますCounter

from collections import Counter

>>> c1 = [1, 2, 2, 3, 4, 4, 4]
>>> c2 = [1, 2, 4, 4, 4, 4, 5]
>>> list((Counter(c1) & Counter(c2)).elements())
[1, 2, 4, 4, 4]

0
# Problem:  Given c1 and c2:
c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
# how do you get c3 to be [[13, 32], [7, 13, 28], [1, 6]] ?

セットc3を含まない設定方法の1つを次に示します。

c3 = []
for sublist in c2:
    c3.append([val for val in c1 if val in sublist])

ただし、1行だけを使用する場合は、次のようにできます。

c3 = [[val for val in c1 if val in sublist]  for sublist in c2]

リスト内包表記の中にあるリスト内包表記ですが、これは少し変わっていますが、私はあなたがそれに続く多くの問題を抱えているべきではないと思います。


0
c1 = [1, 6, 7, 10, 13, 28, 32, 41, 58, 63]
c2 = [[13, 17, 18, 21, 32], [7, 11, 13, 14, 28], [1, 5, 6, 8, 15, 16]]
c3 = [list(set(i) & set(c1)) for i in c2]
c3
[[32, 13], [28, 13, 7], [1, 6]]

私にとってこれは非常にエレガントで迅速な方法です:)


0

フラットリストはreduce簡単に作成できます。

イニシャライザを使用する必要があるすべて- reduce関数の3番目の引数。

reduce(
   lambda result, _list: result.append(
       list(set(_list)&set(c1)) 
     ) or result, 
   c2, 
   [])

上記のコードはpython2とpython3の両方で機能しますが、reduceモジュールをとしてインポートする必要がありますfrom functools import reduce。詳細については、以下のリンクを参照してください。


-1

イテラブル間の違いと共通部分を見つける簡単な方法

繰り返しが重要な場合は、この方法を使用します

from collections import Counter

def intersection(a, b):
    """
    Find the intersection of two iterables

    >>> intersection((1,2,3), (2,3,4))
    (2, 3)

    >>> intersection((1,2,3,3), (2,3,3,4))
    (2, 3, 3)

    >>> intersection((1,2,3,3), (2,3,4,4))
    (2, 3)

    >>> intersection((1,2,3,3), (2,3,4,4))
    (2, 3)
    """
    return tuple(n for n, count in (Counter(a) & Counter(b)).items() for _ in range(count))

def difference(a, b):
    """
    Find the symmetric difference of two iterables

    >>> difference((1,2,3), (2,3,4))
    (1, 4)

    >>> difference((1,2,3,3), (2,3,4))
    (1, 3, 4)

    >>> difference((1,2,3,3), (2,3,4,4))
    (1, 3, 4, 4)
    """
    diff = lambda x, y: tuple(n for n, count in (Counter(x) - Counter(y)).items() for _ in range(count))
    return diff(a, b) + diff(b, a)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.