在Python中比较对象时避免嵌套循环

2024-09-30 14:17:51 发布

您现在位置:Python中文网/ 问答频道 /正文

我得到了两段代码,这两段代码是由不同的人在不同的时间编写的,它们各自都能很好地工作。我的工作是比较这两段代码的输出。我还需要检查某些字段中是否有任何错误。你知道吗

脚本1返回一个Script1Object列表,每个都有自己的属性。类似地,脚本2返回一个Script2Object列表,这些列表与Script1Object相似,但不完全相同。你知道吗

我的代码是这样的:

script1_list = script1()
script2_list = script2()

for item1 in script1_list:
    for item2 in script2_list:
        if is_match(item1, item2):
            do_matching_action()
            break
        elif is_different_match(item1, item2):
            do_other_matching_action()
            break

    if is_bad(item1):
       do_error_action() 

其中is_match()匹配大约10个不同的属性。例如:

def is_match(item1, item2):
    return item1.name == item2.name and item1.ID == item2.number and item1.description.startswith(item2.desc)

is_different_match()is_bad()有一组类似的检查。你知道吗

这样做很好,但速度可能会很慢,尤其是当第一个列表可能有几十万个条目,而第二个列表可能有几千个条目时。代码也不是很模块化,所以我希望避免双for循环可以提高代码的可扩展性。我想知道如何改进这个实现,因为我确信这并没有充分利用Python的特性。你知道吗


Tags: 代码脚本列表for属性ismatchaction
2条回答

我的想法和@slider是一样的,但是你可能会喜欢我的方法。它使用相同的逻辑,首先从第二个脚本中找到列表中的ID。你知道吗

主要的区别是我使用了列表理解,使代码更加紧凑,并避免使用elif。它还跟踪输出列表中不同的匹配元素,以防以后需要访问它们。你知道吗

class A(object):
    def __init__(self, name, ID, desc):
        self.name = name
        self.ID = ID
        self.desc = desc


class B(object):
    def __init__(self, name, ID, desc):
        self.name = name
        self.ID = ID
        self.desc = desc

def do_bad(a):
    print('catch some errors here')
    return a

def do_matching_action(a):
    print('Found match with name = {0}, ID  = {1}, and desc = {2}'.format(a.name, a.ID, a.desc))    
    return a      

item1 = A('name', 1, 'weird_desc')
item2 = A('name', 2, 'weird_desc')
item3 = A('name', 3, 'not_same_desc')
item4 = A('name', 4, 'wei')
item5 = B('name', 1, 'weird_desc')

list1 = [item1, item2, item1, item2, item5]
list2 = [item3, item4, item1, item4, item1]


id_dict = {a.ID: a for a in list2}
common_objects = [a for a in list1 if a.ID in id_dict.keys()]
uncommon_objects = [a for a in list1 if a.ID not in id_dict.keys()]

#peform matching tests
match1 = [do_matching_action(a) for a, b  in common_objects if (a.name == b.name) and (a.ID == b.ID) and a.desc.startswith(b.desc)]

#catch some errors
bad = [do_bad(a) for a in uncommon_objects]

假设匹配对象必须具有相似的id(Script1Object中的IDScript2Object中的number),并且假设script2_list项都具有唯一的number,您可以使用dictionary创建从number到对象的映射。然后,当您进行迭代时,您可以通过字典的number直接从字典中获得一个Script2Object(而不必遍历整个script2_list)。然后可以像以前一样调用两个对象上的每个匹配函数:

script1_list = script1()
script2_list = script2()
script2_dict = {obj.number: obj for obj in script2_list}

for item1 in script1_list:
    item2 = script2_dict.get(item1.ID, None)
    if item2 is None: 
        print('no item2 found for this id: ', item1.ID)
        # do something if there's no matching id
    if is_match(item1, item2):
        do_matching_action()
    elif is_different_match(item1, item2):
        do_other_matching_action()

    if is_bad(item1):
       do_error_action() 

相关问题 更多 >