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 = [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
の代わりにiterableを返すので、filter
の呼び出しをlist()
:でラップする必要があります
c3 = [list(filter(lambda x: x in c1, sublist)) for sublist in c2]
説明:
フィルタ部分は各サブリストの項目を取り、それがソースリストc1にあるかどうかを確認します。リスト内包はc2の各サブリストに対して実行されます。
交差点を定義する必要はありません。それはすでにセットの一流の部分です。
>>> b1 = [1,2,3,4,5,9,11,15]
>>> b2 = [4,5,6,7,8]
>>> set(b1).intersection(b2)
set([4, 5])
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つではなくlist/set間で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)で実行されます。
機能的アプローチ
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+リストのより一般的なケースに適用することができます
>>> 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]]
&演算子は2つの集合の共通部分を取ります。
{1、2、3}&{2、3、4} Out [1]:{2、3}
2つのリストの共通部分をとるPythonicの方法は、次のとおりです。
[x for x in list1 if x in list2]
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]]
このコードを使用して平坦化する必要があります( 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))
与えられた:
> 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(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]
あなたの質問に答えるのが遅れたのかどうかわかりません。あなたの質問を読んだ後、リストとネストしたリストの両方で機能することができる関数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]
[1,2]
は[1, [2]]
と交差すると思いますか?つまり、それはあなたが気にする番号だけなのか、それともリスト構造なのか?
数字だけの場合は、リストを「平坦化」する方法を調べてからset()
メソッドを使用してください。
私はまたそれをする方法を捜していた、そして結局それはこのようになった:
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]
要素の基数を正しく考慮して交差を定義するには、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]
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]]
私にとってこれはとてもエレガントで素早い方法です:)
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]]
これには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
reduce
で簡単に作成できます。使用する必要があるのはinitializer-reduce
関数の3番目の引数です。
reduce(
lambda result, _list: result.append(
list(set(_list)&set(c1))
) or result,
c2,
[])
上記のコードはpython2とpython3の両方で機能しますが、reduceモジュールをfrom functools import reduce
としてインポートする必要があります。詳細については、以下のリンクを参照してください。
# 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]
これはリスト内包内のリスト内包ですが、これはちょっと変わったことですが、それをたどってもそれほど問題はないと思います。