Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can try something like this:</p> <pre><code>list1=[[['B', 10], 1], [['C', 15], 1], [['F', 30], 1]] list2=[[['G', 20], 2], [['D', 25], 1]] list2_iter = iter(list2) for item1 in list1: in_list2 = False for item2 in list2_iter: if item1[1] == item2[1]: print "Match" if item1 == item2 else "Modified", item1, item2 in_list2 = True break else: print "Inserted", item2 if not in_list2: print "Deleted", item1 </code></pre> <p>Note that the inner loop for <code>list2</code> is using an iterator, so it does not start from the beginning of <code>list2</code> each time, but from the last element it stopped in the previous iteration of the outer loop. Everything else is rather straightforward.</p> <p>Output:</p> <pre><code>Inserted [['G', 20], 2] Modified [['B', 10], 1] [['D', 25], 1] Deleted [['C', 15], 1] Deleted [['F', 30], 1] </code></pre> <p>Note that this will not always find the best match, as it will only do one pass through both, <code>list1</code> and <code>list2</code>. For a more complete algorithm, take a look at <a href="http://en.wikipedia.org/wiki/Diff#Algorithm" rel="nofollow">Diff</a> and <a href="http://en.wikipedia.org/wiki/Longest_common_subsequence_problem" rel="nofollow">Longest Common Subsequence</a>.</p> <hr> <p><em>Update:</em> I just realized how this problem is in fact virtually the same as finding the <a href="https://en.wikipedia.org/wiki/Levenshtein_distance" rel="nofollow">minimum edit distance</a> of two strings, for which I just happened to have some code lying around. After some generalization:</p> <pre><code>import operator def diff(s1, s2, match=operator.eq, neutral="*", subst=2): """s1, s2: the two strings or lists to match match: function to determine whether two elements match up neutral: 'neutral' element for padding subst: substitution costs """ s1, s2 = neutral + s1, neutral + s2 # calculate edit distance / sequence match with DP A = [[0] * len(s2) for i in range(len(s1))] for i in range(len(s1)): for k in range(len(s2)): if min(i, k) == 0: A[i][k] = max(i, k) else: diag = 0 if match(s1[i], s2[k]) else subst A[i][k] = min(A[i-1][k-1] + diag, A[i ][k-1] + 1, A[i-1][k ] + 1) # reconstruct path path, i, k = [], len(s1)-1, len(s2)-1 while i or k: if A[i][k] == A[i-1][k] + 1: path, i = [-1] + path, i-1 elif A[i][k] == A[i][k-1] + 1: path, k = [1] + path, k-1 else: path, i, k = [0] + path, i-1, k-1 return A[len(s1)-1][len(s2)-1], path def print_match(list1, list2, path): i1, i2 = iter(list1), iter(list2) for p in path: if p == -1: print "DEL %20r" % next(i1) if p == 0: print "EQ %20r %20r" % (next(i1), next(i2)) if p == +1: print "INS %41r" % next(i2) # with strings word1, word2 = "INTENTION", "EXECUTION" x, path = diff(word1, word2) print_match(word1, word2, path) # with your lists of lists list1 = [[['B', 10], 1], [['C', 15], 1], [['F', 30], 1]] list2 = [[['G', 20], 2], [['D', 25], 1]] x, path = diff(list1, list2, match=lambda x, y: x[1] == y[1], neutral=[[None, -1]]) print_match(list1, list2, path) </code></pre> <p>Note that the resulting match can <em>still</em> be different from what you expect, since often there are many equally optimal ways to match the elements, but it should be optimal nonetheless.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload