在python中找到对象结构相似性的干净有效方法是什么?

时间:2014-03-05 10:48:43

标签: python

考虑一些包含简单类型的python对象,如字符串/ unicode,整数, 列表,http://stardict.sourceforge.net/Dictionaries.php下载。

a = { 'name': 'John'}
b = {'name':'Mathew'}
c = {'name':345}

这里a在结构上类似于b,但不是c,因为c中的值是整数。

更复杂的例子:

a = { 'candidates': [ {'name':'John','age':23},{'name':'Matt','age':23}],'class':{'num':4,'year':2005}}

b = { 'candidates': [ {'name':'Mary','age':33},{'name':'Skipper','age':24}],'class':{'num':14,'year':2006}}

虽然a和b具有不同的值,但它们在相同的键上具有相同类型的值,这也适用于嵌套值。

找到两个这样的python对象相似的好方法是什么? 假设列表将具有统一类型的元素。

我想到的一个想法是递归地比较type个对象成员。

我想知道是否有更容易的hacks或python模块执行此操作?

1 个答案:

答案 0 :(得分:2)

一种解决方案确实是一种递归方法,您可以比较类型:

def compare(v1, v2):
    if not type(v1) == type(v2):
        return False

    if isinstance(v1, dict):
        return compare(sorted(v1.items()), sorted(v2.items()))

    elif isinstance(v1, (list, tuple)):
        if not len(v1) == len(v2):
            return False
        return all(compare(a, b) for a, b in zip(v1, v2))

    return True

此功能适用于您发布的所有案例。但是,如果任何列表在结构之间的长度不同,它将始终返回False。以下是一些结果:

>>> compare({'name':'Mathew'}, {'name':'John'})
True
>>> compare({'name':'Mathew'}, {'name':2})
False
>>> compare([1, 1], [2, 2])
True
>>> compare([1, 2], [1])
False
>>> compare([1, "a"], [2, "b"])
True

如果你想要传递第四个,你可以将list子句分开并仅比较第一个项目,这也假设空列表具有正确的类型:

elif isinstance(v1, list):

    if (not v1) or (not v2):
        return True

    return compare(v1[0], v2[0])

在使用与python一样动态的语言执行此类操作时,您必须非常小心。如果您的输入与您期望的结构略有不同,则很容易出现“错误”结果。例如,如果结构包含集合,则只会对类型进行比较,而不是内容。