Reputation: 2224
In python, it's easy to test whether two variables have the same top-level type:
In [1]: s1 = 'bob'
In [2]: s2 = 'tom'
In [3]: type(s1) == type(s2)
Out[3]: True
But in the case where types are nested, it's not so easy:
In [4]: strlist = ['bob', 'tom']
In [5]: intlist = [5, 6, 7]
In [6]: type(strlist) == type(intlist)
Out[6]: True
Is there a general way to "deeply" compare two variables such that:
deepcompare(['a', 'b'], [1, 2]) == False
deepcompare([42, 43], [1, 2]) == True
?
EDIT:
To define the question a bit more, let's say this includes both list length and heterogeneous list types:
deepcompare([1, 2, 3], [1, 2]) == False
deepcompare([1, 3], [2, 'b']) == False
deepcompare([1, 'a'], [2, 'b']) == True
Upvotes: 3
Views: 951
Reputation: 122032
To expand on my comment, you could create what I've called a "type map" recursively:
def typemap(lst_or_obj):
if not isinstance(lst_or_obj, list):
return type(lst_or_obj)
return [typemap(obj) for obj in lst_or_obj]
Then use this to get the types within your structures:
a = [1, 2, ['three', 4]]
b = [5, 6, ['seven', 8]]
c = [9, 10, [11, 'twelve']]
ta = typemap(a)
tb = typemap(b)
tc = typemap(c)
print(ta)
print(tb)
print(tc)
print(ta == tb)
print(ta == tc)
Output:
[<class 'int'>, <class 'int'>, [<class 'str'>, <class 'int'>]]
[<class 'int'>, <class 'int'>, [<class 'str'>, <class 'int'>]]
[<class 'int'>, <class 'int'>, [<class 'int'>, <class 'str'>]]
True
False
Then your function is simply:
def deepcompare(a, b):
return typemap(a) == typemap(b)
If you need to deal with things other than lists, you can trivially expand the isinstance
check to (list, tuple)
, but you can quickly run into issues with things like str
(recursively iterating over strings is a problem because a single character or empty string is an iterable of itself, so your program explodes) and dict
(ordering issues, comparing keys and/or values, ...).
Upvotes: 2
Reputation: 11807
The way that I do this is by using this function:
def getDeepTypes(items):
types = [type(x) for x in items]
return (types[0] if all(x == types[0] for x in types) else None)
This uses various list comprehensions to get the deep type of a list. If they aren't all the same, None
is returned.
>>> getDeepTypes([1, 2, 3])
int
>>> getDeepTypes(["foo", "bar"])
str
>>> print(getDeepTypes([1, "foo"]))
None
So you could do:
getDeepTypes(['a', 'b']) == getDeepTypes([1, 2]) # False
getDeepTypes([42, 43]) == getDeepTypes([1, 2]) # True
Upvotes: 1