5

我正在用 Python 2.6 (*) 慢慢开发一个数据处理应用程序。我的测试数据非常小,比如 5000 例,但预计在不久的将来会有 100 万例,我想知道我目前的方法在这些条件下是否可行。

问题的结构:我有两个 csv 文件,一个包含调用(5000 行,20 列),另一个包含调用的详细信息(500 行,10 列)。我必须构建第三个 csv 文件,该文件将包含“调用”文件中的所有案例,其中找到了其他详细信息。在幕后有一些繁重的工作(合并和重组细节列表中的数据,列表之间的数据比较)。但我对构建输出列表感到非常紧张:目前代码如下所示:

def reduceOutputListToPossibleMatches(outputList, detailsList):
    reducedList = list()

    for outputItem in outputList:
        isFound = False
        for detailsItem in detailsList:
            if detailsItem[14] == outputItem[4]:
                if isfound:
                    detailsItem[30] = "1" #ambigous case
                                          # - more than one match was found
# 1 is an indicator for true - I am not using python here because spss has no support for booleans.
                isFound = True
        if isFound:
            reducedList.append(detailsItem )

    return reducedList

我认为这个算法需要很长时间,因为我必须循环两个大列表。所以我的问题归结为:Python 中的列表有多快,还有更好的选择吗?另外:双列表处理起来有些不方便,因为我必须记住每列的索引位置 - 有没有更好的选择?

*=我稍后会调用 SPSS 版本 19,它拒绝使用较新版本的 python。

4

2 回答 2

6

从 Elazar 的回答中,使用 dict 来避免内部循环:

def reduceOutputListToPossibleMatches(outputList, detailsList):
    details = {}
    for detailsItem in detailsList:
        key = detailsItem[14]
        if key in details:
            details[key][30] = "1"
        else:
            details[key] = detailsItem

    for outputItem in outputList:
        key = outputItem[4]
        if key in details:
            yield details[key]

res = reduceOutputListToPossibleMatches(outputList, detailsList)
with open('somefile', 'w') as f:
    f.writelines(res)

如果您需要所有模棱两可的行:

def reduceOutputListToPossibleMatches(outputList, detailsList):
    details = {}
    for detailsItem in detailsList:
        key = detailsItem[14]
        if key in details:
            details[key].append(detailsItem)
        else:
            details[key] = [detailsItem]

    for outputItem in outputList:
        key = outputItem[4]
        if key in details:
            for item in details[key]:
                if len(details[key]) > 1:
                    item[30] = "1"
                yield item

res = reduceOutputListToPossibleMatches(outputList, detailsList)
with open('somefile', 'w') as f:
    f.writelines(res)
于 2013-09-25T12:42:14.330 回答
2

我认为您不需要返回list. 你可以这样做:

def reduceOutputListToPossibleMatches(outputList, detailsList):
    for outputItem in outputList:
        isFound = False
        for detailsItem in detailsList:
            if detailsItem[14] == outputItem[4]: #there was a syntax error here
                if isfound:
                    detailsItem[30] = "1"
                    break
                isFound = True
        else:
            yield detailsItem

res = reduceOutputListToPossibleMatches(outputList, detailsList)
with open('somefile', 'w') as f:
    f.writelines(res)

但它仍然O(n**2)很慢。也许 SQL 数据库(通过 Django?)将更适合这项任务。

@Duncan 建议的小改动:

from collections import defaultdict
def reduceOutputListToPossibleMatches(outputList, detailsList):
    details = defaultdict(list)
    for detailsItem in detailsList:
        key = detailsItem[14]
        details[key].append(detailsItem)

    for outputItem in outputList:
        val = details[outputItem[4]]
        if len(val) > 1:
            for item in val:
                item[30] = "1"
        yield from val
于 2013-09-25T12:18:31.543 回答