เปรียบเทียบสองพจนานุกรมและตรวจสอบว่ามีกี่คู่ (คีย์ค่า) เท่ากัน


246

ฉันมีพจนานุกรมสองเล่ม แต่เพื่อความสะดวกฉันจะใช้สองสิ่งนี้:

>>> x = dict(a=1, b=2)
>>> y = dict(a=2, b=2)

ตอนนี้ฉันต้องการเปรียบเทียบว่าแต่ละkey, valueคู่ในxมีค่าที่สอดคล้องกันyหรือไม่ ดังนั้นฉันจึงเขียนสิ่งนี้:

>>> for x_values, y_values in zip(x.iteritems(), y.iteritems()):
        if x_values == y_values:
            print 'Ok', x_values, y_values
        else:
            print 'Not', x_values, y_values

และใช้งานได้เนื่องจาก a tupleถูกส่งคืนแล้วเปรียบเทียบเพื่อความเท่าเทียมกัน

คำถามของฉัน:

ถูกต้องหรือไม่ มีวิธีที่ดีกว่าในการทำเช่นนี้? ไม่ดีกว่าความเร็วฉันกำลังพูดถึงความสง่างามของรหัส

UPDATE: ฉันลืมที่จะพูดถึงว่าฉันต้องตรวจสอบว่ามีกี่key, valueคู่เท่ากัน


21
x == yควรเป็นจริงตามstackoverflow.com/a/5635309/186202
Natim

x == y ควรเป็นจริง หนึ่งสามารถตรวจสอบอย่างรวดเร็วใน REPL โปรดอ้างอิง: docs.python.org/2/library/stdtypes.html#mapping-types-dict
Vikrant

คำตอบ:


179

หากคุณต้องการทราบว่ามีค่าเท่ากันทั้งในพจนานุกรมคุณควรบอกว่า :)

อาจจะเป็นสิ่งนี้:

shared_items = {k: x[k] for k in x if k in y and x[k] == y[k]}
print len(shared_items)

1
ข้อผิดพลาดเดียวกันถ้ามีองค์ประกอบรายการสำหรับคีย์ dict ฉันคิดว่า cmp เป็นวิธีที่ดีกว่าที่จะทำถ้าฉันไม่ได้ทำอะไรเลย
เปลี่ยนแปลง

@Mutant ที่เป็นปัญหาที่แตกต่าง คุณไม่สามารถสร้างพจนานุกรมด้วยlistคีย์ได้ตั้งแต่แรก x = {[1,2]: 2}จะล้มเหลว dictsคำถามที่มีอยู่แล้วที่ถูกต้อง
AnnanFay

@ นัน: ผิดคำถามทั่วไป ตัวอย่างเช่นในรายละเอียดของคำถามที่มีอยู่แล้ว "dicts ถูกต้อง" ถ้าฉันโพสต์คำถามใหม่ด้วยชื่อเดียวกัน แต่ด้วย dict ที่ "ไม่ถูกต้อง" คนอื่นจะทำเครื่องหมายว่าซ้ำกัน downvoting
ribamar

6
@ribamar คำถามคือ "การเปรียบเทียบพจนานุกรมสองเล่ม [... ]" 'dict ที่ไม่ถูกต้อง' ด้านบนพร้อมlistคีย์ไม่ใช่รหัสหลามที่ถูกต้อง - คีย์ dict ต้องไม่เปลี่ยนรูป ดังนั้นคุณไม่ได้เปรียบเทียบพจนานุกรม หากคุณลองและใช้รายการเป็นรหัสพจนานุกรมรหัสของคุณจะไม่ทำงาน คุณไม่มีวัตถุที่จะเปรียบเทียบ นี่เหมือนกับการพิมพ์x = dict(23\;dfg&^*$^%$^$%^)แล้วบ่นว่าการเปรียบเทียบไม่ทำงานกับพจนานุกรมอย่างไร แน่นอนมันจะไม่ทำงาน ความคิดเห็นของ Tim ในทางกลับกันนั้นเกี่ยวกับการเปลี่ยนแปลงvaluesดังนั้นทำไมฉันพูดว่าสิ่งเหล่านี้เป็นปัญหาที่แตกต่างกัน
AnnanFay

1
@MikeyE - setต้องการค่าที่จะแฮชและdictต้องใช้คีย์เพื่อแฮช set(x.keys())จะทำงานเสมอเนื่องจากต้องใช้คีย์เพื่อแฮช แต่set(x.values())จะล้มเหลวกับค่าที่ไม่แฮช
Tim Tisdall

173

สิ่งที่คุณต้องการจะทำก็คือ x==y

สิ่งที่คุณทำไม่ใช่ความคิดที่ดีเพราะรายการในพจนานุกรมไม่ควรมีคำสั่งใด ๆ คุณอาจจะเปรียบเทียบ[('a',1),('b',1)]กับ[('b',1), ('a',1)](พจนานุกรมเดียวกันเรียงลำดับต่างกัน)

ตัวอย่างเช่นดูสิ่งนี้:

>>> x = dict(a=2, b=2,c=3, d=4)
>>> x
{'a': 2, 'c': 3, 'b': 2, 'd': 4}
>>> y = dict(b=2,c=3, d=4)
>>> y
{'c': 3, 'b': 2, 'd': 4}
>>> zip(x.iteritems(), y.iteritems())
[(('a', 2), ('c', 3)), (('c', 3), ('b', 2)), (('b', 2), ('d', 4))]

ความแตกต่างเป็นเพียงรายการเดียว แต่อัลกอริทึมของคุณจะเห็นว่ารายการทั้งหมดแตกต่างกัน


@ THC4k ขอโทษที่ไม่ได้พูดถึง แต่ฉันต้องตรวจสอบว่ามีค่าเท่ากันทั้งในพจนานุกรม
user225312

ตกลงดังนั้นขึ้นอยู่กับการอัปเดตของฉันวิธีการทำยังไม่ถูกต้องหรือไม่?
user225312

@AA: ฉันได้เพิ่มว่าเหตุใดจึงไม่ทำงานเมื่อคุณต้องการนับ
Jochen Ritzel

ฉันเห็น แต่ในกรณีของฉันพจนานุกรมทั้งสองมีความยาวเท่ากัน และพวกเขาจะเป็นเช่นนั้นเสมอเพราะนั่นคือวิธีการทำงานของโปรแกรม
user225312

5
ตั้งแต่ Python 3.6, dict นั้นมีการสั่งซื้อที่ไม่ทันสมัย
Phil

163
def dict_compare(d1, d2):
    d1_keys = set(d1.keys())
    d2_keys = set(d2.keys())
    shared_keys = d1_keys.intersection(d2_keys)
    added = d1_keys - d2_keys
    removed = d2_keys - d1_keys
    modified = {o : (d1[o], d2[o]) for o in shared_keys if d1[o] != d2[o]}
    same = set(o for o in shared_keys if d1[o] == d2[o])
    return added, removed, modified, same

x = dict(a=1, b=2)
y = dict(a=2, b=2)
added, removed, modified, same = dict_compare(x, y)

7
อันนี้จัดการค่าที่ไม่แน่นอนใน dict!
Tim Tisdall

1
เมื่อฉันเรียกใช้สิ่งนี้ฉันยังคงได้รับข้อผิดพลาดที่เห็นการจัดการกับค่าที่ไม่แน่นอน: ValueError: ค่าความจริงของ DataFrame นั้นไม่ชัดเจน ใช้ a.empty, a.bool (), a.item (), a.any () หรือ a.all ()
Afflatus

2
@Afflatus - DataFrames โดยการออกแบบไม่อนุญาตให้มีการเปรียบเทียบ truthy (ยกเว้นว่าจะมีความยาว 1) numpy.ndarrayขณะที่พวกเขาได้รับมรดกจาก -credit to stackoverflow.com/a/33307396/994076
Daniel Myers

นี่คืออัญมณีที่แน่นอน
pfabri

125

dic1 == dic2

จากpython docs :

เพื่อแสดงให้เห็นตัวอย่างต่อไปนี้ทั้งหมดกลับพจนานุกรมเท่ากับ การ {"one": 1, "two": 2, "three": 3}:

>>> a = dict(one=1, two=2, three=3)
>>> b = {'one': 1, 'two': 2, 'three': 3}
>>> c = dict(zip(['one', 'two', 'three'], [1, 2, 3]))
>>> d = dict([('two', 2), ('one', 1), ('three', 3)])
>>> e = dict({'three': 3, 'one': 1, 'two': 2})
>>> a == b == c == d == e
True

การระบุอาร์กิวเมนต์คำหลักตามตัวอย่างแรกใช้ได้กับคีย์ที่เป็นตัวระบุ Python ที่ถูกต้องเท่านั้น มิฉะนั้นคีย์ที่ถูกต้องสามารถใช้งานได้

คูปองสำหรับทั้งสองและpy2py3


3
ฉันไม่เห็นด้วยกับ @ ErkinAlpGüney คุณสามารถแสดงหลักฐานได้หรือไม่?
Qi Luo

4
ฉันไม่เห็นด้วยกับ @ ErkinAlpGüney เอกสารอย่างเป็นทางการแสดงให้เห็นว่า == จริง ๆ แล้วเปรียบเทียบพจนานุกรมตามค่าไม่ใช่ตามที่อยู่ docs.python.org/2/library/stdtypes.html#mapping-types-dict
Matthew Nakayama

3
ใช้งานได้กับ Python 2.7.13
Jesuisme

4
@ankostis:OrderedDict != dict
CONVID19

3
คุณกรุณาให้ข้อมูลที่ไม่เป็นความจริงได้หรือไม่?
CONVID19 19

55

ฉันใหม่กับงูใหญ่ แต่ฉันก็ลงเอยทำสิ่งที่คล้ายกับ @mouad

unmatched_item = set(dict_1.items()) ^ set(dict_2.items())
len(unmatched_item) # should be 0

ตัวดำเนินการ XOR ( ^) ควรกำจัดองค์ประกอบทั้งหมดของ dict เมื่อพวกมันเหมือนกันใน dicts ทั้งสอง


28
น่าเสียดายที่สิ่งนี้ไม่ทำงานหากค่าใน dict นั้นไม่แน่นอน (เช่นไม่แฮช) (ตัวอย่าง{'a':{'b':1}}ให้TypeError: unhashable type: 'dict')
Tim Tisdall

54

เนื่องจากดูเหมือนว่าไม่มีใครพูดถึงdeepdiffฉันจะเพิ่มที่นี่เพื่อความสมบูรณ์ ฉันคิดว่ามันสะดวกในการรับวัตถุที่แตกต่างกัน (โดยทั่วไป):

การติดตั้ง

pip install deepdiff

โค้ดตัวอย่าง

import deepdiff
import json

dict_1 = {
    "a": 1,
    "nested": {
        "b": 1,
    }
}

dict_2 = {
    "a": 2,
    "nested": {
        "b": 2,
    }
}

diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(diff, indent=4))

เอาท์พุต

{
    "values_changed": {
        "root['a']": {
            "new_value": 2,
            "old_value": 1
        },
        "root['nested']['b']": {
            "new_value": 2,
            "old_value": 1
        }
    }
}

หมายเหตุเกี่ยวกับการพิมพ์ผลลัพธ์สำหรับการตรวจสอบอย่างสวยหรู: โค้ดด้านบนใช้งานได้ถ้า dicts ทั้งคู่มีคีย์แอ็ตทริบิวต์ที่เหมือนกัน อย่างไรก็ตามหากมี"extra"แอตทริบิวต์เป็นหนึ่งใน dicts json.dumps()ล้มเหลวด้วย

TypeError: Object of type PrettyOrderedSet is not JSON serializable

วิธีแก้ไข: ใช้diff.to_json()และjson.loads()/ json.dumps()เพื่อพิมพ์สวย:

import deepdiff
import json

dict_1 = {
    "a": 1,
    "nested": {
        "b": 1,
    },
    "extra": 3
}

dict_2 = {
    "a": 2,
    "nested": {
        "b": 2,
    }
}

diff = deepdiff.DeepDiff(dict_1, dict_2)
print(json.dumps(json.loads(diff.to_json()), indent=4))  

เอาท์พุท:

{
    "dictionary_item_removed": [
        "root['extra']"
    ],
    "values_changed": {
        "root['a']": {
            "new_value": 2,
            "old_value": 1
        },
        "root['nested']['b']": {
            "new_value": 2,
            "old_value": 1
        }
    }
}

ทางเลือก: ใช้pprintส่งผลให้การจัดรูปแบบแตกต่างกัน:

import pprint

# same code as above

pprint.pprint(diff, indent=4)

เอาท์พุท:

{   'dictionary_item_removed': [root['extra']],
    'values_changed': {   "root['a']": {   'new_value': 2,
                                           'old_value': 1},
                          "root['nested']['b']": {   'new_value': 2,
                                                     'old_value': 1}}}

2
น่าสนใจ ขอบคุณที่ตอบคำถามนี้ มีประโยชน์สำหรับฉันอย่างน้อย คำตอบนี้ต้องการ upvotes เพิ่มเติม
Archit Kapoor

46

เพียงใช้:

assert cmp(dict1, dict2) == 0

6
ดูเหมือนว่างานไม่เพียง แต่จะตรวจสอบว่าเนื้อหาของทั้งสองเหมือนกัน แต่ยังให้รายงานความแตกต่าง
Diego Tercero

29
ฉันเชื่อว่านี่เหมือนกันกับdict1 == dict2
Trey Hunner

10
สำหรับทุกคนที่ใช้ Python3.5 การcmpสร้างในจะถูกลบออก (และควรจะถูกกำจัดเหมือนก่อนหน้านี้ทางเลือกที่เสนอ: (a > b) - (a < b) == cmp(a, b)สำหรับการทำงานเทียบเท่า (หรือดีกว่า__eq__และ__hash__)
nerdwaller

3
@nerdwaller - dicts ไม่ใช่ประเภทที่สั่งซื้อได้ดังนั้น dict_a> dict_b จะยกระดับTypeError:unorderable types: dict() < dict()
Stefano

2
@Stefano: โทรดีความคิดเห็นของฉันเป็นมากกว่าการเปรียบเทียบทั่วไปในหลาม (ฉันไม่ได้ใส่ใจกับคำตอบที่เกิดขึ้นจริงความผิดพลาดของฉัน)
nerdwaller

9

@mouad คำตอบนั้นดีถ้าคุณคิดว่าพจนานุกรมทั้งสองนั้นมีค่าอย่างง่ายเท่านั้น อย่างไรก็ตามหากคุณมีพจนานุกรมที่มีพจนานุกรมคุณจะได้รับการยกเว้นเนื่องจากพจนานุกรมไม่สามารถแฮชได้

จากด้านบนของหัวของฉันบางอย่างเช่นนี้อาจทำงานได้:

def compare_dictionaries(dict1, dict2):
     if dict1 is None or dict2 is None:
        print('Nones')
        return False

     if (not isinstance(dict1, dict)) or (not isinstance(dict2, dict)):
        print('Not dict')
        return False

     shared_keys = set(dict1.keys()) & set(dict2.keys())

     if not ( len(shared_keys) == len(dict1.keys()) and len(shared_keys) == len(dict2.keys())):
        print('Not all keys are shared')
        return False


     dicts_are_equal = True
     for key in dict1.keys():
         if isinstance(dict1[key], dict) or isinstance(dict2[key], dict):
             dicts_are_equal = dicts_are_equal and compare_dictionaries(dict1[key], dict2[key])
         else:
             dicts_are_equal = dicts_are_equal and all(atleast_1d(dict1[key] == dict2[key]))

     return dicts_are_equal

หากคุณใช้not isinstance(dict1, dict)แทนtype(dict1) is not dictสิ่งนี้จะทำงานกับคลาสอื่น ๆ โดยยึดตามdict. Also, instead of (dict1 [key] == dict2 [key]) , you can do ทั้งหมด (atleast_1d (dict1 [key] == dict2 [key])) `เพื่อจัดการอาร์เรย์อย่างน้อย
EL_DON

+1 แต่คุณสามารถแยกออกจากคุณfor loopทันทีที่คุณdicts_are_equalกลายเป็นเท็จ ไม่จำเป็นต้องดำเนินการใด ๆ เพิ่มเติม
pfabri

6

ความเป็นไปได้อีกอย่างหนึ่งที่ถึงโน้ตสุดท้ายของ OP คือการเปรียบเทียบแฮช ( SHAหรือMD) ของ dicts ที่ถูกเททิ้งเป็น JSON วิธีแฮชถูกสร้างขึ้นรับประกันว่าถ้าพวกเขามีความเท่าเทียมกันสตริงที่มาจะเหมือนกัน นี่คือเสียงที่รวดเร็วและทางคณิตศาสตร์

import json
import hashlib

def hash_dict(d):
    return hashlib.sha1(json.dumps(d, sort_keys=True)).hexdigest()

x = dict(a=1, b=2)
y = dict(a=2, b=2)
z = dict(a=1, b=2)

print(hash_dict(x) == hash_dict(y))
print(hash_dict(x) == hash_dict(z))

2
นั่นเป็นสิ่งที่ผิดอย่างสมบูรณ์การแยกวิเคราะห์ข้อมูลลงใน json นั้นช้ามาก จากนั้นการคร่ำครวญสิ่งที่คุณสร้างขึ้นนั้นยิ่งแย่ไปกว่านั้น คุณไม่ควรทำอย่างนั้น
บรูโน

7
@Bruno: อ้าง OP: "ดีไม่ได้อยู่ในความเร็วที่ผมพูดถึงความสง่างามรหัส"
WoJ

2
มันไม่หรูหราเลยรู้สึกไม่ปลอดภัยและมันซับซ้อนเกินไปสำหรับปัญหาที่เรียบง่ายจริงๆ
Bruno

7
@Bruno: ความสง่างามเป็นอัตนัย ฉันสามารถเข้าใจว่าคุณไม่ชอบมัน (และอาจ downvote) สิ่งนี้ไม่เหมือนกับ "ผิด"
WoJ

4
นี่คือคำตอบที่ดี json.dumps(d, sort_keys=True)จะให้ JSON แบบบัญญัติกับคุณเพื่อให้คุณมั่นใจได้ว่า dict ทั้งสองนั้นเทียบเท่ากัน นอกจากนี้ยังขึ้นอยู่กับสิ่งที่คุณพยายามที่จะบรรลุ ทันทีที่ค่าไม่ปรับ JSON จะทำให้ล้มเหลว สำหรับใครที่บอกว่ามันไม่มีประสิทธิภาพให้ดูที่โครงการ ujson
Natim

6

ฟังก์ชั่นนี้ใช้ IMO ได้ดีชัดเจนและใช้งานง่าย แต่เพียงเพื่อให้คำตอบ (อีก) คุณนี่คือไปของฉัน:

def compare_dict(dict1, dict2):
    for x1 in dict1.keys():
        z = dict1.get(x1) == dict2.get(x1)
        if not z:
            print('key', x1)
            print('value A', dict1.get(x1), '\nvalue B', dict2.get(x1))
            print('-----\n')

มีประโยชน์สำหรับคุณหรือคนอื่น ..

แก้ไข:

ฉันได้สร้างเวอร์ชันแบบเรียกซ้ำจากด้านบน .. ไม่เห็นว่าในคำตอบอื่น ๆ

def compare_dict(a, b):
    # Compared two dictionaries..
    # Posts things that are not equal..
    res_compare = []
    for k in set(list(a.keys()) + list(b.keys())):
        if isinstance(a[k], dict):
            z0 = compare_dict(a[k], b[k])
        else:
            z0 = a[k] == b[k]

        z0_bool = np.all(z0)
        res_compare.append(z0_bool)
        if not z0_bool:
            print(k, a[k], b[k])
    return np.all(res_compare)

2
มาปรับปรุงกันเถอะมันใช้งานได้ทั้งสองทาง บรรทัดที่ 2: "สำหรับ x1 ในชุด (dict1.keys ()). union (dict2.keys ()):"
nkadwa

ขอบคุณ @nkadwa ตอนนี้ก็ทำได้แล้ว
zwep

5

ในการทดสอบว่าสอง dicts เท่ากันในคีย์และค่า:

def dicts_equal(d1,d2):
    """ return True if all keys and values are the same """
    return all(k in d2 and d1[k] == d2[k]
               for k in d1) \
        and all(k in d1 and d1[k] == d2[k]
               for k in d2)

หากคุณต้องการส่งคืนค่าที่ต่างกันให้เขียนต่างกัน:

def dict1_minus_d2(d1, d2):
    """ return the subset of d1 where the keys don't exist in d2 or
        the values in d2 are different, as a dict """
    return {k,v for k,v in d1.items() if k in d2 and v == d2[k]}

คุณจะต้องเรียกมันสองครั้งคือ

dict1_minus_d2(d1,d2).extend(dict1_minus_d2(d2,d1))

3

รหัส

def equal(a, b):
    type_a = type(a)
    type_b = type(b)
    
    if type_a != type_b:
        return False
    
    if isinstance(a, dict):
        if len(a) != len(b):
            return False
        for key in a:
            if key not in b:
                return False
            if not equal(a[key], b[key]):
                return False
        return True

    elif isinstance(a, list):
        if len(a) != len(b):
            return False
        while len(a):
            x = a.pop()
            index = indexof(x, b)
            if index == -1:
                return False
            del b[index]
        return True
        
    else:
        return a == b

def indexof(x, a):
    for i in range(len(a)):
        if equal(x, a[i]):
            return i
    return -1

ทดสอบ

>>> a = {
    'number': 1,
    'list': ['one', 'two']
}
>>> b = {
    'list': ['two', 'one'],
    'number': 1
}
>>> equal(a, b)
True

3

การเปรียบเทียบแบบง่าย ๆ กับ == น่าจะเพียงพอแล้วในปัจจุบัน (python 3.8) แม้ว่าคุณจะเปรียบเทียบ dicts เดียวกันในลำดับอื่น (ตัวอย่างล่าสุด) สิ่งที่ดีที่สุดคือคุณไม่จำเป็นต้องใช้แพ็คเกจของบุคคลที่สามเพื่อทำสิ่งนี้ให้สำเร็จ

a = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
b = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}

c = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}
d = {'one': 'dog', 'two': 'cat', 'three': 'mouse', 'four': 'fish'}

e = {'one': 'cat', 'two': 'dog', 'three': 'mouse'}
f = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}

g = {'two': 'cat', 'one': 'dog', 'three': 'mouse'}
h = {'one': 'dog', 'two': 'cat', 'three': 'mouse'}


print(a == b) # True
print(c == d) # False
print(e == f) # False
print(g == h) # True

2

การมาสายของฉันตอบสนองดีกว่าไม่เคย!

เปรียบเทียบ Not_Equal มีประสิทธิภาพมากกว่าการเปรียบเทียบเท่ากับ เช่นสอง dicts นั้นไม่เท่ากันหากค่าคีย์ใด ๆ ใน dict หนึ่งไม่พบใน dict อื่น โค้ดด้านล่างคำนึงถึงว่าคุณอาจเปรียบเทียบ dict ที่เป็นค่าเริ่มต้นและใช้ get แทนgetitem []

การใช้ค่าสุ่มชนิดเป็นค่าเริ่มต้นในการรับสายเท่ากับคีย์ที่ถูกเรียกคืน - ในกรณีที่ dicts ไม่มีค่าเป็นค่าในหนึ่ง dict และคีย์นั้นไม่มีอยู่ในอีกค่า นอกจากนี้ยังได้รับการตรวจสอบเงื่อนไขก่อน! ไม่ได้อยู่ในสภาพเพื่อประสิทธิภาพเนื่องจากคุณกำลังทำการตรวจสอบคีย์และค่าจากทั้งสองด้านในเวลาเดียวกัน

def Dicts_Not_Equal(first,second):
    """ return True if both do not have same length or if any keys and values are not the same """
    if len(first) == len(second): 
        for k in first:
            if first.get(k) != second.get(k,k) or k not in second: return (True)
        for k in second:         
            if first.get(k,k) != second.get(k) or k not in first: return (True)
        return (False)   
    return (True)

2

ฉันใช้โซลูชันนี้ซึ่งทำงานได้อย่างสมบูรณ์แบบสำหรับฉันใน Python 3


import logging
log = logging.getLogger(__name__)

...

    def deep_compare(self,left, right, level=0):
        if type(left) != type(right):
            log.info("Exit 1 - Different types")
            return False

        elif type(left) is dict:
            # Dict comparison
            for key in left:
                if key not in right:
                    log.info("Exit 2 - missing {} in right".format(key))
                    return False
                else:
                    if not deep_compare(left[str(key)], right[str(key)], level +1 ):
                        log.info("Exit 3 - different children")
                        return False
            return True
        elif type(left) is list:
            # List comparison
            for key in left:
                if key not in right:
                    log.info("Exit 4 - missing {} in right".format(key))
                    return False
                else:
                    if not deep_compare(left[left.index(key)], right[right.index(key)], level +1 ):
                        log.info("Exit 5 - different children")
                        return False
            return True
        else:
            # Other comparison
            return left == right

        return False

มันเปรียบเทียบ dict รายการและประเภทอื่น ๆ ที่ใช้ตัวดำเนินการ "==" ด้วยตัวเอง หากคุณต้องการเปรียบเทียบสิ่งอื่นที่แตกต่างกันคุณจะต้องเพิ่มสาขาใหม่ใน "if tree"

หวังว่าจะช่วย



1
>>> hash_1
{'a': 'foo', 'b': 'bar'}
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_1 = set (hash_1.iteritems())
>>> set_1
set([('a', 'foo'), ('b', 'bar')])
>>> set_2 = set (hash_2.iteritems())
>>> set_2
set([('a', 'foo'), ('b', 'bar')])
>>> len (set_1.difference(set_2))
0
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...    print "The two hashes match."
...
The two hashes match.
>>> hash_2['c'] = 'baz'
>>> hash_2
{'a': 'foo', 'c': 'baz', 'b': 'bar'}
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
>>>
>>> hash_2.pop('c')
'baz'

นี่คือตัวเลือกอื่น:

>>> id(hash_1)
140640738806240
>>> id(hash_2)
140640738994848

ดังนั้นเมื่อคุณเห็นรหัสทั้งสองนั้นแตกต่างกัน แต่ผู้ประกอบการเปรียบเทียบที่ร่ำรวยดูเหมือนจะหลอกลวง:

>>> hash_1 == hash_2
True
>>>
>>> hash_2
{'a': 'foo', 'b': 'bar'}
>>> set_2 = set (hash_2.iteritems())
>>> if (len(set_1.difference(set_2)) | len(set_2.difference(set_1))) == False:
...     print "The two hashes match."
...
The two hashes match.
>>>

1

ใน PyUnit มีวิธีการเปรียบเทียบพจนานุกรมที่สวยงาม ฉันทดสอบโดยใช้สองพจนานุกรมต่อไปนี้และทำสิ่งที่คุณกำลังมองหา

d1 = {1: "value1",
      2: [{"subKey1":"subValue1",
           "subKey2":"subValue2"}]}
d2 = {1: "value1",
      2: [{"subKey2":"subValue2",
           "subKey1": "subValue1"}]
      }


def assertDictEqual(self, d1, d2, msg=None):
        self.assertIsInstance(d1, dict, 'First argument is not a dictionary')
        self.assertIsInstance(d2, dict, 'Second argument is not a dictionary')

        if d1 != d2:
            standardMsg = '%s != %s' % (safe_repr(d1, True), safe_repr(d2, True))
            diff = ('\n' + '\n'.join(difflib.ndiff(
                           pprint.pformat(d1).splitlines(),
                           pprint.pformat(d2).splitlines())))
            standardMsg = self._truncateMessage(standardMsg, diff)
            self.fail(self._formatMessage(msg, standardMsg))

ฉันไม่แนะนำให้นำเข้าunittestสู่รหัสการผลิตของคุณ ความคิดของฉันคือแหล่งที่มาใน PyUnit อาจได้รับการจัดทำเครื่องมือใหม่เพื่อให้ทำงานได้ มันใช้pprintสิ่งที่ "พิมพ์สวย" พจนานุกรม ดูเหมือนง่ายที่จะดัดแปลงรหัสนี้เป็น "พร้อมการผลิต"


1

ดูวัตถุดูพจนานุกรม: https://docs.python.org/2/library/stdtypes.html#dict

วิธีนี้คุณสามารถลบ dictView2 จาก dictView1 และจะส่งคืนชุดของคู่คีย์ / ค่าที่แตกต่างใน dictView2:

original = {'one':1,'two':2,'ACTION':'ADD'}
originalView=original.viewitems()
updatedDict = {'one':1,'two':2,'ACTION':'REPLACE'}
updatedDictView=updatedDict.viewitems()
delta=original | updatedDict
print delta
>>set([('ACTION', 'REPLACE')])

คุณสามารถตัดกัน, สหภาพ, ความแตกต่าง (แสดงด้านบน), ความแตกต่างแบบสมมาตรวัตถุมุมมองพจนานุกรมเหล่านี้
ดีขึ้นหรือไม่ ได้เร็วขึ้น? - ไม่แน่ใจ แต่เป็นส่วนหนึ่งของไลบรารีมาตรฐาน - ซึ่งทำให้เป็นข้อดีสำหรับการพกพา


1

โค้ดด้านล่างจะช่วยให้คุณเปรียบเทียบรายการ dict ใน python

def compate_generic_types(object1, object2):
    if isinstance(object1, str) and isinstance(object2, str):
        return object1 == object2
    elif isinstance(object1, unicode) and isinstance(object2, unicode):
        return object1 == object2
    elif isinstance(object1, bool) and isinstance(object2, bool):
        return object1 == object2
    elif isinstance(object1, int) and isinstance(object2, int):
        return object1 == object2
    elif isinstance(object1, float) and isinstance(object2, float):
        return object1 == object2
    elif isinstance(object1, float) and isinstance(object2, int):
        return object1 == float(object2)
    elif isinstance(object1, int) and isinstance(object2, float):
        return float(object1) == object2

    return True

def deep_list_compare(object1, object2):
    retval = True
    count = len(object1)
    object1 = sorted(object1)
    object2 = sorted(object2)
    for x in range(count):
        if isinstance(object1[x], dict) and isinstance(object2[x], dict):
            retval = deep_dict_compare(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False
        elif isinstance(object1[x], list) and isinstance(object2[x], list):
            retval = deep_list_compare(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False
        else:
            retval = compate_generic_types(object1[x], object2[x])
            if retval is False:
                print "Unable to match [{0}] element in list".format(x)
                return False

    return retval

def deep_dict_compare(object1, object2):
    retval = True

    if len(object1) != len(object2):
        return False

    for k in object1.iterkeys():
        obj1 = object1[k]
        obj2 = object2[k]
        if isinstance(obj1, list) and isinstance(obj2, list):
            retval = deep_list_compare(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False

        elif isinstance(obj1, dict) and isinstance(obj2, dict):
            retval = deep_dict_compare(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False
        else:
            retval = compate_generic_types(obj1, obj2)
            if retval is False:
                print "Unable to match [{0}]".format(k)
                return False

    return retval

3
ยินดีต้อนรับสู่ Stack Overflow! ในขณะที่ข้อมูลโค้ดนี้อาจแก้ปัญหาได้รวมถึงคำอธิบายช่วยปรับปรุงคุณภาพของโพสต์ของคุณ จำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตและคนเหล่านั้นอาจไม่ทราบสาเหตุของการแนะนำรหัสของคุณ โปรดอย่าพยายามทำให้รหัสของคุณแน่นเกินไปด้วยคำอธิบายที่อธิบายซึ่งจะช่วยลดความสามารถในการอ่านของทั้งรหัสและคำอธิบาย!
Filnor

1
>>> x = {'a':1,'b':2,'c':3}
>>> x
{'a': 1, 'b': 2, 'c': 3}

>>> y = {'a':2,'b':4,'c':3}
>>> y
{'a': 2, 'b': 4, 'c': 3}

METHOD 1:

>>> common_item = x.items()&y.items() #using union,x.item() 
>>> common_item
{('c', 3)}

METHOD 2:

 >>> for i in x.items():
        if i in y.items():
           print('true')
        else:
           print('false')


false
false
true

0

ใน Python 3.6 สามารถทำได้ดังนี้: -

if (len(dict_1)==len(dict_2): 
  for i in dict_1.items():
        ret=bool(i in dict_2.items())

ตัวแปร ret จะเป็นจริงถ้าทุกรายการของ dict_1 ที่มีอยู่ใน dict_2


0

นี่คือคำตอบของฉันใช้วิธีเรียกซ้ำ:

def dict_equals(da, db):
    if not isinstance(da, dict) or not isinstance(db, dict):
        return False
    if len(da) != len(db):
        return False
    for da_key in da:
        if da_key not in db:
            return False
        if not isinstance(db[da_key], type(da[da_key])):
            return False
        if isinstance(da[da_key], dict):
            res = dict_equals(da[da_key], db[da_key])
            if res is False:
                return False
        elif da[da_key] != db[da_key]:
            return False
    return True

a = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
b = {1:{2:3, 'name': 'cc', "dd": {3:4, 21:"nm"}}}
print dict_equals(a, b)

หวังว่าจะช่วย!


0

ทำไมไม่ลองทำซ้ำในพจนานุกรมหนึ่งและตรวจสอบอีกขั้นตอนหนึ่ง (สมมติว่าพจนานุกรมทั้งสองมีรหัสเหมือนกัน)

x = dict(a=1, b=2)
y = dict(a=2, b=2)

for key, val in x.items():
    if val == y[key]:
        print ('Ok', val, y[key])
    else:
        print ('Not', val, y[key])

เอาท์พุท:

Not 1 2
Ok 2 2

0

วิธีที่ง่ายที่สุด (และหนึ่งในโปรแกรมที่มีประสิทธิภาพมากขึ้น) เพื่อทำการเปรียบเทียบอย่างลึกของพจนานุกรมสองภาษาคือการจัดเรียงในรูปแบบ JSON เรียงลำดับคีย์และเปรียบเทียบผลลัพธ์สตริง:

import json
if json.dumps(x, sort_keys=True) == json.dumps(y, sort_keys=True):
   ... Do something ...

-7
import json

if json.dumps(dict1) == json.dumps(dict2):
    print("Equal")

1
สิ่งนี้อาจไม่ทำสิ่งที่ร้องขออย่างแน่นอนและดึงใน json std lib แต่ทำงานได้ (ตามที่json.dumpsกำหนดไว้กับการตั้งค่าเริ่มต้น)
Daniel Farrell
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.