2012-05-07 25 views
17

Làm cách nào để kiểm tra xem hai từ điển có bình đẳng không khi xem xét một số khóa. Ví dụ:So sánh các từ điển bỏ qua các khóa cụ thể

equal_dicts(
    {'foo':1, 'bar':2, 'x':55, 'y': 77 }, 
    {'foo':1, 'bar':2, 'x':66, 'z': 88 }, 
    ignore_keys=('x', 'y', 'z') 
) 

phải trả về True.

UPD: Tôi đang tìm một giải pháp nhanh và hiệu quả.

UPD2. Tôi đã kết thúc với mã này, mà dường như là nhanh nhất:

def equal_dicts_1(a, b, ignore_keys): 
    ka = set(a).difference(ignore_keys) 
    kb = set(b).difference(ignore_keys) 
    return ka == kb and all(a[k] == b[k] for k in ka) 

Thời gian: https://gist.github.com/2651872

Trả lời

14
def equal_dicts(d1, d2, ignore_keys): 
    d1_filtered = dict((k, v) for k,v in d1.iteritems() if k not in ignore_keys) 
    d2_filtered = dict((k, v) for k,v in d2.iteritems() if k not in ignore_keys) 
    return d1_filtered == d2_filtered 

EDIT: Đây có thể là nhanh hơn và bộ nhớ hiệu quả:

def equal_dicts(d1, d2, ignore_keys): 
    ignored = set(ignore_keys) 
    for k1, v1 in d1.iteritems(): 
     if k1 not in ignored and (k1 not in d2 or d2[k1] != v1): 
      return False 
    for k2, v2 in d2.iteritems(): 
     if k2 not in ignored and k2 not in d1: 
      return False 
    return True 
+0

+1 (tốt hơn so với câu trả lời của tôi!) Ngoài ra, nếu một trong những xảy ra được sử dụng Python 3, bạn có thể sử dụng một [dict comprehension] (http://docs.python.org/py3k/tutorial/datastructures.html#dictionaries) (cuộn xuống một chút) thay cho 'd ict () 'thành ngữ. – huon

+0

Đây là một giải pháp đơn giản, nhưng trong vấn đề hiệu quả tình hình của tôi. – georg

+0

@ thg435 - xem câu trả lời cập nhật của tôi. – eumiro

0

Rất rất thô lỗ, bạn chỉ có thể xóa mọi phím bị bỏ qua và so sánh các từ điển đó:

def equal_dicts(d1, d2, ignore_keys=()): 
    d1_, d2_ = d1.copy(), d2.copy() 
    for k in ignore_keys: 
     try: 
      del d1_[k] 
     except KeyError: 
      pass 
     try: 
      del d2_[k] 
     except KeyError: 
      pass 

    return d1_ == d2_ 

(Lưu ý rằng chúng ta không cần một bản sao sâu ở đây, chúng ta chỉ cần tránh thay đổi d1d2.)

+1

thô thực sự)))) – georg

1
def compare_dict(d1, d2, ignore): 
    for k in d1: 
     if k in ignore: 
      continue 
     try: 
      if d1[k] != d2[k]: 
       return False 
     except KeyError: 
      return False 
    return True 

Comment chỉnh sửa: Bạn có thể làm điều gì đó như compare_dict(d1, d2, ignore) and compare_dict(d2, d1, ignore) hoặc lặp lại trong các for

def compare_dict(d1, d2, ignore): 
    ignore = set(ignore) 
    for k in d1: 
     if k in ignore: 
      continue 
     try: 
      if d1[k] != d2[k]: 
       return False 
     except KeyError: 
      return False 

    for k in d2: 
     if k in ignore: 
      continue 
     try: 
      if d1[k] != d2[k]: 
       return False 
     except KeyError: 
      return False 
    return True 

Mọi thứ nhanh hơn và sạch hơn! Cập nhật: dàn diễn viên bộ (bỏ qua)

+1

Cảm ơn, nhưng tôi không nghĩ rằng điều này sẽ làm việc khi 'd2' có thêm phím. – georg

8
{k: v for k,v in d1.iteritems() if k not in ignore_keys} == {k: v for k,v in d2.iteritems() if k not in ignore_keys} 
+0

Điều này sẽ hoạt động trong Python 2.7 và 3. –

+0

Cảm ơn, nhưng hãy xem nhận xét của tôi về câu trả lời của eumiro. Tôi không muốn xây dựng hai cấu trúc bộ nhớ đắt tiền chỉ để so sánh chúng. – georg

+0

sau đó bạn có thể viết vòng lặp bằng tay, nhưng bạn có thể thấy hiểu nhanh hơn vì thực hiện C – wim

0

giải pháp tối ưu đối với trường hợp chỉ bỏ qua một chìa khóa

return all(
    (x == y or (x[1] == y[1] == 'key to ignore')) for x, y in itertools.izip(
      d1.iteritems(), d2.iteritems())) 
+0

Hãy coi chừng: điều này có thể không hoạt động chính xác trong mọi trường hợp trong các phiên bản Python cũ hơn (ví dụ: bảng băm có kích thước khác nhau v.v.), nhưng việc thực hiện tương tự chắc chắn còn hoạt động trong Python 3.6+ bởi vì các phương thức dict.items() etc hiện trả về các mục theo thứ tự chèn, không phải là thứ tự hashtable. – intgr

0

trong trường hợp từ điển của bạn chứa danh sách hoặc các từ điển khác:

def equal_dicts(d1, d2, ignore_keys, equal): 
    # print('got d1', d1) 
    # print('got d2', d2) 
    if isinstance(d1, str): 
     if not isinstance(d2, str): 
      return False 
     return d1 == d2 
    for k in d1: 
     if k in ignore_keys: 
      continue 
     if not isinstance(d1[k], dict) and not isinstance(d1[k], list) and d2.get(k) != d1[k]: 
      print(k) 
      equal = False 
     elif isinstance(d1[k], list): 
      if not isinstance(d2.get(k), list): 
       equal = False 
      if len(d1[k]) != len(d2[k]): 
       return False 
      if len(d1[k]) > 0 and isinstance(d1[k][0], dict): 
       if not isinstance(d2[k][0], dict): 
        return False 
       d1_sorted = sorted(d1[k], key=lambda item: item.get('created')) 
       d2_sorted = sorted(d2[k], key=lambda item: item.get('created')) 
       equal = all(equal_dicts(x, y, ignore_keys, equal) for x, y in zip(d1_sorted, d2_sorted)) and equal 
      else: 
       equal = all(equal_dicts(x, y, ignore_keys, equal) for x, y in zip(d1[k], d2[k])) and equal 
     elif isinstance(d1[k], dict): 
      if not isinstance(d2.get(k), dict): 
       equal = False 
      print(k) 
      equal = equal_dicts(d1[k], d2[k], ignore_keys, equal) and equal 
    return equal 
Các vấn đề liên quan