Python 2 列表比较优化

1 投票
2 回答
513 浏览
提问于 2025-04-16 23:33

给定的情况:

有两个csv文件(每个文件大小为1.8 MB):AllData_1和AllData_2。每个文件大约有8000行。每一行包含8列数据。

目标:

根据txt_0的匹配(也就是说,AllData_1的第一列等于AllData_2的第一列),比较这两行的接下来的4列内容。如果这些数据不相等,就把每组数据的整行放到一个列表里,列表是根据不同的列来分类的,并把这些列表保存到输出文件中。如果txt_0在一个数据集中存在,但在另一个数据集中不存在,那么就直接把这个数据保存到输出文件中。

举个例子:

AllData_1的某一行x包含:[a1, b2, c3, d4, e5, f6, g7, h8],而AllData_2的某一行y包含:[a1, b2, c33c, d44d, e5, f6, g7, h8]

程序会把行x和行y都保存到对应的列表ListCol2和ListCol3中。在所有比较完成后,这些列表会被保存到文件里。

我该如何让我的代码更快,或者把我的代码改成更快的算法呢?

i = 0
x0list = []
y0list = []
col1_diff = col2_diff = col3a_diff = col3b_diff = col4_diff = []

#create list out of column 0
for y in AllData_2:
    y0list.append(y[0])

for entry in AllData_1:
    x0list.append(entry[0])
    if entry[0] not in y0list:
        #code to save the line to file...

for y0 in AllData_2:
    if y0[0] not in x0list:
        #code to save the line to file...

for yrow in AllData_2:
    i+=1

    for xrow in AllData_1:
        foundit = 0
        if yrow[0] == xrow[0] and foundit == 0 and (yrow[1] != xrow[1] or yrow[2] != xrow[2] or yrow[3] != xrow[3] or yrow[4] != xrow[4]):
            if yrow[1] != xrow[1]:
                col1_diff.append(yrow)
                col1_diff.append(xrow)
                foundit = 1

            elif yrow[2] != xrow[2]:
                col2_diff.append(yrow)
                col2_diff.append(xrow)
                foundit = 1

            elif len(yrow[3]) < len(xrow[3]):
                col3a_diff.append(yrow)
                col3a_diff.append(xrow)
                foundit = 1

            elif len(yrow[3]) >= len(xrow[3]):
                col3b_diff.append(yrow)
                col3b_diff.append(xrow)
                foundit = 1

            else:
                #col4 is actually a catch-all for any other differences between lines if [0]s are equal
                col4_diff.append(yrow)
                col4_diff.append(xrow)
                foundit = 1

2 个回答

1

一开始,你可以把这个缩小很多。

y0list = []
for y in AllData_2:
    y0list.append(y[0])

这只是说得比较啰嗦的一种表达方式。

y0list = [y[0] for y in AllData_2]

而且你可以在内置的比较中使用它。

下面这个

(yrow[1] != xrow[1] or yrow[2] != xrow[2] or yrow[3] != xrow[3] or yrow[4] != xrow[4])

可以用

yrow[1:] != xrow[1:]

来表示,这样更不容易出现复制粘贴的错误。

为了让它更快,你可以避免做 O(n**2) 的比较。因为你只关心第一列的元素是否相同,所以你可以根据第一个元素来进行分组。

index = {}
for yrow in AllData_2:
    key = yrow[0]
    list = index.get(key)
    if list is None:
        list = []
        index[key] = list
    list.append(yrow)

for xrow in AllData_1:
    list = index.get(xrow[0])
    if list is None: continue
    for yrow in list:
        # Do all your comparison here
1

如果你能确保在一个文件中,第一列的每一行数据都是不一样的,那么你可以通过使用几个 dict(字典)来大幅提升你的代码效率。这样,你就不需要像下面这样处理每一行:

x0list.append(entry[0])
y0list.append(y[0])

你可以用下面的方式:

x0dict[entry[0]] = entry
y0dict[y[0]] = y

在初始化 x0dicty0dict{} 之后。然后,你就不需要再遍历所有的数据,而只需遍历其中一个字典:

for x0, xrow in x0dict:
    if x0 in y0dict:
        yrow = y0dict[x0]
        # Do the col{1,2,3,4}_diff stuff here

另外,你在第二和第三个循环中使用的 not in 也能正常工作。


这一行:

(yrow[1] != xrow[1] or yrow[2] != xrow[2] or yrow[3] != xrow[3] or yrow[4] != xrow[4])

可以换成更好看的:

yrow[1:5] != xrow[1:5]

目前你的代码中,i 这个变量没有被用到,但如果你需要这个计数,它其实和直接写 i = len(AllData_2) 是一样的,因为在遍历 AllData_2 的循环中,它每次只增加一次。


最后,你的 foundit 变量现在没有任何用处。它只是用来控制流程的,像 foundit == 0 这样的判断,设置为0后总是会返回 True,所以设置它并没有实际效果。

撰写回答