2つのリストの違いを取得します
-
27-09-2019 - |
質問
Pythonには2つのリストがあります。
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two']
2番目のリストには存在しない最初のリストのアイテムを含む3番目のリストを作成する必要があります。私が取得する必要がある例から:
temp3 = ['Three', 'Four']
サイクルやチェックなしの速い方法はありますか?
解決
In [5]: list(set(temp1) - set(temp2))
Out[5]: ['Four', 'Three']
それに注意してください
In [5]: set([1, 2]) - set([2, 3])
Out[5]: set([1])
あなたがそれが等しくなることを期待する/望むかもしれない場所 set([1, 3])
. 。あなたが欲しいなら set([1, 3])
あなたの答えとして、あなたは使用する必要があります set([1, 2]).symmetric_difference(set([2, 3]))
.
他のヒント
既存のソリューションはすべて、次のいずれかを提供します。
- O(n*m)パフォーマンスよりも速い。
- 入力リストの順序を保持します。
しかし、これまでのところ、両方の解決策はありません。両方が必要な場合は、これを試してみてください。
s = set(temp2)
temp3 = [x for x in temp1 if x not in s]
性能テスト
import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print timeit.timeit('list(set(temp1) - set(temp2))', init, number = 100000)
print timeit.timeit('s = set(temp2);[x for x in temp1 if x not in s]', init, number = 100000)
print timeit.timeit('[item for item in temp1 if item not in temp2]', init, number = 100000)
結果:
4.34620224079 # ars' answer
4.2770634955 # This answer
30.7715615392 # matt b's answer
私が提示した方法と保存順序は、不要なセットの構築を必要としないため、セット減算よりも(わずかに)速いです。最初のリストが2番目のリストよりもかなり長く、ハッシュが高価である場合、パフォーマンスの違いはより顕著になります。これを実証する2番目のテストです。
init = '''
temp1 = [str(i) for i in range(100000)]
temp2 = [str(i * 2) for i in range(50)]
'''
結果:
11.3836875916 # ars' answer
3.63890368748 # this answer (3 times faster!)
37.7445402279 # matt b's answer
temp3 = [item for item in temp1 if item not in temp2]
2つのリスト(List1とList2など)の違いは、次の単純な関数を使用して見つけることができます。
def diff(list1, list2):
c = set(list1).union(set(list2)) # or c = set(list1) | set(list2)
d = set(list1).intersection(set(list2)) # or d = set(list1) & set(list2)
return list(c - d)
また
def diff(list1, list2):
return list(set(list1).symmetric_difference(set(list2))) # or return list(set(list1) ^ set(list2))
上記の関数を使用することにより、違いは diff(temp2, temp1)
また diff(temp1, temp2)
. 。どちらも結果を与えます ['Four', 'Three']
. 。リストの順序や、最初にどのリストを指定するかを心配する必要はありません。
違いを再帰的にしたい場合は、Python用のパッケージを書きました。https://github.com/seperman/deepdiff
インストール
Pypiからのインストール:
pip install deepdiff
使用の例
インポート
>>> from deepdiff import DeepDiff
>>> from pprint import pprint
>>> from __future__ import print_function # In case running on Python 2
同じオブジェクトが空に戻ります
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = t1
>>> print(DeepDiff(t1, t2))
{}
アイテムの種類が変更されました
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:"2", 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{ 'type_changes': { 'root[2]': { 'newtype': <class 'str'>,
'newvalue': '2',
'oldtype': <class 'int'>,
'oldvalue': 2}}}
アイテムの価値が変更されました
>>> t1 = {1:1, 2:2, 3:3}
>>> t2 = {1:1, 2:4, 3:3}
>>> pprint(DeepDiff(t1, t2), indent=2)
{'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
追加および/または削除されたアイテム
>>> t1 = {1:1, 2:2, 3:3, 4:4}
>>> t2 = {1:1, 2:4, 3:3, 5:5, 6:6}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff)
{'dic_item_added': ['root[5]', 'root[6]'],
'dic_item_removed': ['root[4]'],
'values_changed': {'root[2]': {'newvalue': 4, 'oldvalue': 2}}}
文字列の違い
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world"}}
>>> t2 = {1:1, 2:4, 3:3, 4:{"a":"hello", "b":"world!"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { 'root[2]': {'newvalue': 4, 'oldvalue': 2},
"root[4]['b']": { 'newvalue': 'world!',
'oldvalue': 'world'}}}
文字列の違い2
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world!\nGoodbye!\n1\n2\nEnd"}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n1\n2\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'values_changed': { "root[4]['b']": { 'diff': '--- \n'
'+++ \n'
'@@ -1,5 +1,4 @@\n'
'-world!\n'
'-Goodbye!\n'
'+world\n'
' 1\n'
' 2\n'
' End',
'newvalue': 'world\n1\n2\nEnd',
'oldvalue': 'world!\n'
'Goodbye!\n'
'1\n'
'2\n'
'End'}}}
>>>
>>> print (ddiff['values_changed']["root[4]['b']"]["diff"])
---
+++
@@ -1,5 +1,4 @@
-world!
-Goodbye!
+world
1
2
End
タイプの変更
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":"world\n\n\nEnd"}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'type_changes': { "root[4]['b']": { 'newtype': <class 'str'>,
'newvalue': 'world\n\n\nEnd',
'oldtype': <class 'list'>,
'oldvalue': [1, 2, 3]}}}
リストの違い
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3, 4]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{'iterable_item_removed': {"root[4]['b'][2]": 3, "root[4]['b'][3]": 4}}
リストの違い2:
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'iterable_item_added': {"root[4]['b'][3]": 3},
'values_changed': { "root[4]['b'][1]": {'newvalue': 3, 'oldvalue': 2},
"root[4]['b'][2]": {'newvalue': 2, 'oldvalue': 3}}}
注文または複製を無視する違いの違い:(上記と同じ辞書で)
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, 3]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 3, 2, 3]}}
>>> ddiff = DeepDiff(t1, t2, ignore_order=True)
>>> print (ddiff)
{}
辞書を含むリスト:
>>> t1 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:1, 2:2}]}}
>>> t2 = {1:1, 2:2, 3:3, 4:{"a":"hello", "b":[1, 2, {1:3}]}}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (ddiff, indent = 2)
{ 'dic_item_removed': ["root[4]['b'][2][2]"],
'values_changed': {"root[4]['b'][2][1]": {'newvalue': 3, 'oldvalue': 1}}}
セット:
>>> t1 = {1, 2, 8}
>>> t2 = {1, 2, 3, 5}
>>> ddiff = DeepDiff(t1, t2)
>>> pprint (DeepDiff(t1, t2))
{'set_item_added': ['root[3]', 'root[5]'], 'set_item_removed': ['root[8]']}
名前付きのタプル:
>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> t1 = Point(x=11, y=22)
>>> t2 = Point(x=11, y=23)
>>> pprint (DeepDiff(t1, t2))
{'values_changed': {'root.y': {'newvalue': 23, 'oldvalue': 22}}}
カスタムオブジェクト:
>>> class ClassA(object):
... a = 1
... def __init__(self, b):
... self.b = b
...
>>> t1 = ClassA(1)
>>> t2 = ClassA(2)
>>>
>>> pprint(DeepDiff(t1, t2))
{'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
追加されたオブジェクト属性:
>>> t2.c = "new attribute"
>>> pprint(DeepDiff(t1, t2))
{'attribute_added': ['root.c'],
'values_changed': {'root.b': {'newvalue': 2, 'oldvalue': 1}}}
本当にパフォーマンスを調べている場合は、Numpyを使用してください!
これは、リスト、Numpy、およびPandasの比較を持つGitHubの要点としての完全なノートブックです。
https://gist.github.com/denfromufa/2821ff59b02e9482be15d27f2bd4451
最も簡単な方法、
使用する set()。差(set())
list_a = [1,2,3]
list_b = [2,3]
print set(list_a).difference(set(list_b))
答えはです set([1])
リストとして印刷できます、
print list(set(list_a).difference(set(list_b)))
現在のソリューションはどれもタプルを生成しないので、私は投げ込みます:
temp3 = tuple(set(temp1) - set(temp2))
または、
#edited using @Mark Byers idea. If you accept this one as answer, just accept his instead.
temp3 = tuple(x for x in temp1 if x not in set(temp2))
この方向に他の非タプルの譲歩の答えのように、それは順序を保持します
Python XORオペレーターを使用して実行できます。
- これにより、各リストの複製が削除されます
- これにより、TEMP1とTEMP1からのTEMP2の違いが示されます。
set(temp1) ^ set(temp2)
私は2つのリストを取り、何をすることができるかを望んでいました diff
の bash
します。この質問は、「Python Diff 2つのリスト」を検索すると最初に表示され、あまり具体的ではないので、私が思いついたものを投稿します。
使用 SequenceMather
から difflib
次の2つのリストを比較できます diff
します。他の答えはどれも、違いが発生する位置を教えてくれませんが、これはそうします。いくつかの答えは、一方向のみに違いを与えます。要素を並べ替える人もいます。複製を処理しない人もいます。しかし、このソリューションは、2つのリスト間の真の違いを与えます。
a = 'A quick fox jumps the lazy dog'.split()
b = 'A quick brown mouse jumps over the dog'.split()
from difflib import SequenceMatcher
for tag, i, j, k, l in SequenceMatcher(None, a, b).get_opcodes():
if tag == 'equal': print('both have', a[i:j])
if tag in ('delete', 'replace'): print(' 1st has', a[i:j])
if tag in ('insert', 'replace'): print(' 2nd has', b[k:l])
これは出力です:
both have ['A', 'quick']
1st has ['fox']
2nd has ['brown', 'mouse']
both have ['jumps']
2nd has ['over']
both have ['the']
1st has ['lazy']
both have ['dog']
もちろん、あなたのアプリケーションが他の答えがするのと同じ仮定をした場合、あなたはそれらから最も利益を得るでしょう。しかし、あなたが真実を探しているなら diff
機能性、これが唯一の方法です。
たとえば、他の答えはどれも処理できませんでした。
a = [1,2,3,4,5]
b = [5,4,3,2,1]
しかし、これは次のとおりです。
2nd has [5, 4, 3, 2]
both have [1]
1st has [2, 3, 4, 5]
これを試して:
temp3 = set(temp1) - set(temp2)
これは、マークのリスト理解よりもさらに高速になる可能性があります。
list(itertools.filterfalse(set(temp2).__contains__, temp1))
これが次のとおりです Counter
最も単純なケースの回答。
これは、双方向の違いを実行する上記のものよりも短いです。なぜなら、質問が正確に尋ねることのみを行うからです。最初のリストのリストを生成しますが、2番目のリストではありません。
from collections import Counter
lst1 = ['One', 'Two', 'Three', 'Four']
lst2 = ['One', 'Two']
c1 = Counter(lst1)
c2 = Counter(lst2)
diff = list((c1 - c2).elements())
または、読みやすさの好みに応じて、まともなワンライナーになります。
diff = list((Counter(lst1) - Counter(lst2)).elements())
出力:
['Three', 'Four']
削除できることに注意してください list(...)
あなたがそれを繰り返しているなら、電話してください。
このソリューションはカウンターを使用しているため、多くのセットベースの回答を適切に処理します。たとえば、この入力について:
lst1 = ['One', 'Two', 'Two', 'Two', 'Three', 'Three', 'Four']
lst2 = ['One', 'Two']
出力は次のとおりです。
['Two', 'Two', 'Three', 'Three', 'Four']
Difflistの要素がソートされ、セットがある場合は、素朴な方法を使用できます。
list1=[1,2,3,4,5]
list2=[1,2,3]
print list1[len(list2):]
またはネイティブセットの方法で:
subset=set(list1).difference(list2)
print subset
import timeit
init = 'temp1 = list(range(100)); temp2 = [i * 2 for i in range(50)]'
print "Naive solution: ", timeit.timeit('temp1[len(temp2):]', init, number = 100000)
print "Native set solution: ", timeit.timeit('set(temp1).difference(temp2)', init, number = 100000)
ナイーブソリューション:0.0787101593292
ネイティブセットソリューション:0.998837615564
私はこのゲームで少し遅すぎますが、上記のコードのいくつかのパフォーマンスをこれと比較することができます。2つの最速の候補者は、
list(set(x).symmetric_difference(set(y)))
list(set(x) ^ set(y))
基本レベルのコーディングについてお詫び申し上げます。
import time
import random
from itertools import filterfalse
# 1 - performance (time taken)
# 2 - correctness (answer - 1,4,5,6)
# set performance
performance = 1
numberoftests = 7
def answer(x,y,z):
if z == 0:
start = time.clock()
lists = (str(list(set(x)-set(y))+list(set(y)-set(y))))
times = ("1 = " + str(time.clock() - start))
return (lists,times)
elif z == 1:
start = time.clock()
lists = (str(list(set(x).symmetric_difference(set(y)))))
times = ("2 = " + str(time.clock() - start))
return (lists,times)
elif z == 2:
start = time.clock()
lists = (str(list(set(x) ^ set(y))))
times = ("3 = " + str(time.clock() - start))
return (lists,times)
elif z == 3:
start = time.clock()
lists = (filterfalse(set(y).__contains__, x))
times = ("4 = " + str(time.clock() - start))
return (lists,times)
elif z == 4:
start = time.clock()
lists = (tuple(set(x) - set(y)))
times = ("5 = " + str(time.clock() - start))
return (lists,times)
elif z == 5:
start = time.clock()
lists = ([tt for tt in x if tt not in y])
times = ("6 = " + str(time.clock() - start))
return (lists,times)
else:
start = time.clock()
Xarray = [iDa for iDa in x if iDa not in y]
Yarray = [iDb for iDb in y if iDb not in x]
lists = (str(Xarray + Yarray))
times = ("7 = " + str(time.clock() - start))
return (lists,times)
n = numberoftests
if performance == 2:
a = [1,2,3,4,5]
b = [3,2,6]
for c in range(0,n):
d = answer(a,b,c)
print(d[0])
elif performance == 1:
for tests in range(0,10):
print("Test Number" + str(tests + 1))
a = random.sample(range(1, 900000), 9999)
b = random.sample(range(1, 900000), 9999)
for c in range(0,n):
#if c not in (1,4,5,6):
d = answer(a,b,c)
print(d[1])
これは別の解決策です:
def diff(a, b):
xa = [i for i in set(a) if i not in b]
xb = [i for i in set(b) if i not in a]
return xa + xb
あなたが遭遇した場合 TypeError: unhashable type: 'list'
リストまたはセットをタプルに変える必要があります。
set(map(tuple, list_of_lists1)).symmetric_difference(set(map(tuple, list_of_lists2)))
参照してください Pythonのリスト/セットのリストを比較する方法は?
ここにいくつかの単純なものがあります、 注文予約 文字列の2つのリストを拡張する方法。
コード
使用を使用した珍しいアプローチ pathlib
:
import pathlib
temp1 = ["One", "Two", "Three", "Four"]
temp2 = ["One", "Two"]
p = pathlib.Path(*temp1)
r = p.relative_to(*temp2)
list(r.parts)
# ['Three', 'Four']
これは、両方のリストに同等の始まりを持つ文字列が含まれていることを前提としています。を参照してください ドキュメント 詳細については。操作の設定と比較して、特に高速ではありません。
使用した簡単な実装 itertools.zip_longest
:
import itertools as it
[x for x, y in it.zip_longest(temp1, temp2) if x != y]
# ['Three', 'Four']
のシングルラインバージョン arulmr 解決
def diff(listA, listB):
return set(listA) - set(listB) | set(listA) -set(listB)
あなたがもっとチェンジセットのようなものが欲しいなら...カウンターを使用することができます
from collections import Counter
def diff(a, b):
""" more verbose than needs to be, for clarity """
ca, cb = Counter(a), Counter(b)
to_add = cb - ca
to_remove = ca - cb
changes = Counter(to_add)
changes.subtract(to_remove)
return changes
lista = ['one', 'three', 'four', 'four', 'one']
listb = ['one', 'two', 'three']
In [127]: diff(lista, listb)
Out[127]: Counter({'two': 1, 'one': -1, 'four': -2})
# in order to go from lista to list b, you need to add a "two", remove a "one", and remove two "four"s
In [128]: diff(listb, lista)
Out[128]: Counter({'four': 2, 'one': 1, 'two': -1})
# in order to go from listb to lista, you must add two "four"s, add a "one", and remove a "two"
リストの交差点を引いたマイナスユニオンを計算できます。
temp1 = ['One', 'Two', 'Three', 'Four']
temp2 = ['One', 'Two', 'Five']
set(temp1+temp2)-(set(temp1)&set(temp2))
Out: set(['Four', 'Five', 'Three'])
これは1つの行で解決できます。質問には、2つのリスト(TEMP1とTEMP2)が3番目のリスト(TEMP3)に違いを返します。
temp3 = list(set(temp1).difference(set(temp2)))
2つのリストがあるとしましょう
list1 = [1, 3, 5, 7, 9]
list2 = [1, 2, 3, 4, 5]
上記の2つのリストから、項目1、3、5がList2に存在し、項目7、9が存在しないことがわかります。一方、項目1、3、5はlist1に存在し、項目2、4は存在しません。
アイテム7、9、2、4を含む新しいリストを返すための最良のソリューションは何ですか?
上記のすべての回答は解決策を見つけますが、今では最も最適なものは何ですか?
def difference(list1, list2):
new_list = []
for i in list1:
if i not in list2:
new_list.append(i)
for j in list2:
if j not in list1:
new_list.append(j)
return new_list
対
def sym_diff(list1, list2):
return list(set(list1).symmetric_difference(set(list2)))
TimeITを使用すると、結果が表示されます
t1 = timeit.Timer("difference(list1, list2)", "from __main__ import difference,
list1, list2")
t2 = timeit.Timer("sym_diff(list1, list2)", "from __main__ import sym_diff,
list1, list2")
print('Using two for loops', t1.timeit(number=100000), 'Milliseconds')
print('Using two for loops', t2.timeit(number=100000), 'Milliseconds')
戻り値
[7, 9, 2, 4]
Using two for loops 0.11572412995155901 Milliseconds
Using symmetric_difference 0.11285737506113946 Milliseconds
Process finished with exit code 0
2つのリスト(コンテンツが何であれ)を区別する簡単な方法を以下に示します。以下に示すように結果を得ることができます。
>>> from sets import Set
>>>
>>> l1 = ['xvda', False, 'xvdbb', 12, 'xvdbc']
>>> l2 = ['xvda', 'xvdbb', 'xvdbc', 'xvdbd', None]
>>>
>>> Set(l1).symmetric_difference(Set(l2))
Set([False, 'xvdbd', None, 12])
これが役立つことを願っています。
(list(set(a)-set(b))+list(set(b)-set(a)))