比循环查找数据更快更好的方法?

时间:2017-04-06 01:07:47

标签: python python-2.7 for-loop

我有一个类对象数组,如下所示,thisRate首先设置为None

class Person(object):
    def __init__(self, id, name):
        self.id = id
        self.name = name
        self.thisRate= None

我将大约21K Person个对象加载到一个数组中,name没有排序。

然后我从一个文件中加载了另一个数组,该文件包含thisRate的数据,其中约有13K,name也没有排序:

person_data = []

# read from file
row['name'] = 'Peter'
row['thisRate'] = '0.12334'

person_data.append(row)

现在有了这两组数组,当它们之间匹配name时,我会将thisRate中的person_data分配到Person.thisRate

我正在做的是循环是这样的:

for person in persons:
    data = None
    try:
        data = next(personData for personData in person_data
                        if personData['name'] == person.name)
    except StopIteration:
        print("No rate for this person: {}".format(person.name))

    if data:
        person.thisRate = float( data['thisRate'] )

此循环

data = next(personData for personData in person_data
                if personData['name'] == person.name)

运行正常,使用Python 2.7.13在我的机器上使用21秒。

我的问题是,有没有更快或更好的方法来实现我拥有的2个数组相同的东西?

1 个答案:

答案 0 :(得分:4)

是。制作从namethisRate的词典:

nd = {}

with open(<whatever>) as f:
    reader = csv.DictReader(<whatever>):
    for row in reader:
        nd[row['name']] = row['thisRate'] 

现在,使用此词典对Person列表进行一次传递:

for person in persons:
    thisRate = nd.get(person.name, None)
    person.thisRate = thisRate
    if thisRate is None:
        print("No rate for this person: {}".format(person.name))

字典有.get方法,允许您在密钥不在dict时提供默认值。我使用None(实际上是默认的默认值),但你可以使用你想要的任何东西。

这是线性时间解决方案。你的解决方案是二次时间,因为你基本上是这样做的:

for person in persons:
    for data in person_data:
        if data['name'] == person.name:
            person.thisRate = data['thisRate']
            break
    else:
        print("No rate for this person: {}".format(person.name))

只是以一种方式掩盖了生成器表达式中基本上嵌套的for循环(对于生成器表达式来说不是一个很好的用例),你应该刚开始使用for循环,然后你不要# 39; t必须处理try-catchStopIteration