Skip to content

Instantly share code, notes, and snippets.

@durden
Last active December 10, 2015 23:55
Show Gist options
  • Save durden/4512414 to your computer and use it in GitHub Desktop.
Save durden/4512414 to your computer and use it in GitHub Desktop.
Snippet of timing/brainstorming multiple solutions to compare two lists without worrying about ordering
# See the following for a discussion I later found on stackoverflow, should
# have searched there first ;)
# http://stackoverflow.com/questions/1388818/how-can-i-compare-two-lists-in-python-and-return-matches
from timeit import timeit
# Different ways to implement a function that compares lists without
# taking into account their order
compare_lists_without_order = lambda x, y: sorted(x) == sorted(y)
compare_lists_without_order = lambda x, y: True if not len(set(x) - set(y)) else False
compare_lists_without_order = lambda x, y: True if set(x).intersection(y) == set(x) else False
def compare_lists_without_order(x, y):
if len(x) != len(y):
return False
for val1 in x:
if val1 not in y:
return False
return True
# Not saying any of these solutions are 'good,' just brainstorming. The set solutions
# have some overhead of actually creating sets, etc. This got me to thinking, which
# comparison method is 'faster?'
# Lists are not sorted
timeit('sorted(x) != sorted(y)', setup='x = range(10);y = range(9, -1, -1)')
#1.1857669353485107
timeit('set(x).intersection(y)', setup='x = range(10);y = range(9, -1, -1)')
#1.1229619979858398
timeit('set(x) - set(y)', setup='x = range(10);y = range(9, -1, -1)')
#1.2803409099578857
timeit('compare_lists_without_order(x, y)', setup='x = range(10);y = range(9, -1, -1);from __main__ import compare_lists_without_order')
#1.5430231094360352
# Lists are already sorted
timeit('set(x) - set(y)', setup='x = range(10);y = range(10)')
#1.2265610694885254
timeit('set(x).intersection(y)', setup='x = range(10);y = range(10)')
#1.0897159576416016
timeit('sorted(x) != sorted(y)', setup='x = range(10);y = range(10)')
#1.1469509601593018
timeit('compare_lists_without_order(x, y)', setup='x = range(10);y = range(10);from __main__ import compare_lists_without_order')
#1.5693888664245605
## Final thoughts
# --------------------------------
# I think the direct solution that manually does the looping and checking the lengths
# might be best. It's slower, but it's a bit easier to understand and doesn't require
# converting to sets, etc. In addition, it will give the right answer if you deem the
# right answer to mean that the sets have exactly the same items just in a different
# (or same) order.
# Note that the two solutions with set will not return the correct result depending on what
# you want. Consider the following two lists:
x = range(10)
y = range(10) + [1]
# y has duplicates but using the following comparison we will not detect this
compare_lists_without_order = lambda x, y: True if not len(set(x) - set(y)) else False
compare_lists_without_order(x, y)
# Note that the order you do the set difference doesn't matter; remember sets don't
# allow duplicates so the sets created from the two lists are actually equal
compare_lists_without_order = lambda x, y: True if not len(set(y) - set(x)) else False
compare_lists_without_order(x, y)
# The intersection solution falls victim to the same problem:
compare_lists_without_order = lambda x, y: True if set(x).intersection(y) == set(x) else False
compare_lists_without_order(x,y)
# Of course the set solutions could be 'fixed' by adding a check in each of them to
# ensure that the lists are the same length, just as the full/direct loop solution
# used.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment