2017-03-05 6 views
1

私は2つのintリストxsとys(任意の長さ)を持っており、各リストに表示される重複を効率的に削除したい。あなたが/それをあなたとループをリストを編集しないでくださいすることはできませんので、私の試みでした:値は、xsではなく、一度YSに二度まで来るPythonで2つのリストから一致を見つけて削除する

matches = [match for match in xs if match in ys] 
for match in matches: 
    xs.remove(match) 
    ys.remove(match) 

しかし、重要なことならば、これは以来、エラーを生成します"ys内の一致"は同じ値に対して2回trueと評価されますが、1回だけカウントする必要があります。

のであれば、明確にする:

xs = [0, 2, 4, 8, 8, 100] 
ys = [1, 3, 5, 8, 8, 8, 10] 

その後、8つのニーズが両方のリストから2回削除されます。

これを効率的に行うにはどうすればよいですか?ありがとう

編集:リストは必ずしも順序付けされていません。実際には両方のリストに重複が含まれている可能性があります。

答えて

4

交差点にマルチセット(collections.Counter)を使用できます。多数の重複が予想され、リストが大きい場合、.removeは高価なので避けることをお勧めします。リストの理解度ははるかに優れています。私たちはいくつかの控えめなitertoolsトリッキーを使用して、マークされた重複を除外します。あなたの要素はハッシュ可能です場合にのみ動作することに注意してください

from collections import Counter 
from itertools import repeat, chain 

xc = Counter(xs) 
yc = Counter(ys) 
matches = xc & yc 
tr = repeat(True) 
rm = {k: chain(repeat(False, m), tr) for k, m in matches.items()} 
xs = [x for x in xs if not x in rm or next(rm[x])] 
rm = {k: chain(repeat(False, m), tr) for k, m in matches.items()} 
ys = [y for y in ys if not y in rm or next(rm[y])] 

たとえばなどを最初に削除ではなく、最後の発生しないように、これは適合させることができることに注意してください。

+1

これは2重複でしか動作しませんが、n重複ではないため、この例を更新しました。 –

+0

@BenJonesああ、わかります。明確にできますか?この状況でどうなるべきか: 'xs = [1,1,1,1,2]' 'ys = [1,1,3]'?望ましい出力? 'xs = [1,1,1,2]' 'ys = [1,3']?または 'xs = [1,1,2]' 'ys = [3]'または 'xs = [1,2]' 'ys = [3]'? –

+0

両方のリストに共通の2つの1がありますので、希望の出力はxs = [1,1,2]とys = [3]です。混乱して申し訳ありません! –

関連する問題