2012-01-29 64 views
5

Tôi có hai danh sách kết quả kiểm tra. Các kết quả xét nghiệm được biểu diễn dưới dạng từ điển:So sánh danh sách từ điển

list1 = [{testclass='classname', testname='testname', testtime='...},...] 
list2 = [{testclass='classname', testname='testname', ...},...] 

Các đại diện từ điển là hơi khác nhau trong cả hai danh sách, bởi vì đối với một danh sách tôi có một số chi tiết thông tin. Nhưng trong mọi trường hợp, mọi từ điển thử nghiệm trong một danh sách sẽ có một phần tử tên lớp và testname cùng nhau tạo thành một cách xác định duy nhất thử nghiệm và cách so sánh nó trong danh sách.

Tôi cần phải tìm ra tất cả các thử nghiệm có trong danh sách1 nhưng không có trong danh sách 2, vì chúng đại diện cho các lỗi kiểm tra mới.

Để thực hiện điều này, tôi làm:

def get_new_failures(list1, list2): 
    new_failures = [] 
    for test1 in list1: 
     for test2 in list2: 
      if test1['classname'] == test2['classname'] and \ 
        test1['testname'] == test2['testname']: 
       break; # Not new breakout of inner loop 
     # Doesn't match anything must be new 
     new_failures.append(test1); 
    return new_failures; 

tôi tự hỏi là một con trăn cách hơn để làm điều này. Tôi nhìn vào bộ lọc. Chức năng bộ lọc sử dụng sẽ cần phải có được một xử lý cho cả hai danh sách. Một là dễ dàng, nhưng tôi không chắc chắn làm thế nào nó sẽ có được một xử lý cho cả hai. Tôi biết nội dung của danh sách cho đến khi thời gian chạy.

Bất kỳ trợ giúp nào sẽ được đánh giá cao,

Cảm ơn.

+0

lỗi chính tả @Wooble cố định – dublintech

Trả lời

8

Hãy thử điều này:

def get_new_failures(list1, list2): 
    check = set([(d['classname'], d['testname']) for d in list2]) 
    return [d for d in list1 if (d['classname'], d['testname']) not in check] 
+1

+1, đây là ý nghĩ tiếp theo tôi có - Tôi không nhận thấy bạn đã đăng nó. – senderle

2

Nếu mỗi kết hợp classnametestname thực sự là duy nhất, thì cách tiếp cận hiệu quả hơn về mặt tính toán sẽ là sử dụng hai từ điển thay vì hai danh sách. Là chìa khóa của từ điển, hãy sử dụng một bộ dữ liệu như sau: (classname, testname). Sau đó, bạn có thể chỉ cần nói if (classname, testname) in d: ....

Nếu bạn cần giữ lại thứ tự chèn và đang sử dụng Python 2.7 trở lên, bạn có thể sử dụng OrderedDict từ mô-đun collections.

Mã này sẽ giống như thế này:

tests1 = {('classname', 'testname'):{'testclass':'classname', 
            'testname':'testname',...}, 
     ...} 
tests2 = {('classname', 'testname'):{'testclass':'classname', 
            'testname':'testname',...}, 
     ...} 

new_failures = [t for t in tests1 if t not in tests2] 

Nếu bạn phải sử dụng danh sách đối với một số lý do, bạn có thể duyệt qua list2 để tạo ra một bộ, và sau đó thử nghiệm cho các thành viên trong tập hợp đó:

test1_tuples = ((d['classname'], d['testname']) for d in test1) 
test2_tuples = set((d['classname'], d['testname']) for d in test2) 
new_failures = [t for t in test1_tuples if t not in test2_tuples] 
+0

mã của bạn hoạt động tốt, nhưng nó có một lỗi đánh máy trong 'test2_tuples = ...' dòng - một ngoặc đơn là mất tích –

+0

@ ÓscarLópez, quả thật vậy, nhờ ! Đã sửa lỗi. – senderle

2

Để so sánh hai dict d1d2 trên một tập hợp con của các phím của họ, sử dụng:

all(d1[k] == d2[k] for k in ('testclass', 'testname')) 

Và nếu hai danh sách của bạn có cùng chiều dài, bạn có thể sử dụng zip() để ghép nối chúng.

+3

Nhưng điều này vẫn yêu cầu lặp lại trên sản phẩm Descartes của hai danh sách ... – senderle

+0

@senderle: Nếu anh ta có hai danh sách, tôi không thấy vấn đề trong đó. –

Các vấn đề liên quan