Openpyxl 和二进制搜索
Openpyxl and Binary Search
问题:我有两个传播sheet。 Spreadsheet 1 有大约 20,000 行。 Spreadsheet 2 有近 100 万行。当 spreadsheet 1 中一行的值与 spreadsheet 2 中一行的值匹配时,spreadsheet 2 中的整行被写入 excel。题目不是太难,但是行数如此之多,运行时间长得令人难以置信。
第 1 本书示例:
|键|值|
|------|--------------------|
|397241|587727227839578000|
第 2 本书的示例:
ID
a
b
c
587727227839578000
393
24
0.43
我目前的解决方案是:
g1 = openpyxl.load_workbook('path/to/sheet/sheet1.xlsx',read_only=True)
grid1 = g1.active
grid1_rows = list(grid1.rows)
g2 = openpyxl.load_workbook('path/to/sheet2/sheet2.xlsx',read_only=True)
grid2 = g2.active
grid2_rows = list(grid2.rows)
for row in grid1_rows:
value1 = int(row[1].value)
print(value1)
for row2 in grid2_rows:
value2 = int(row2[0].value)
if value1 == value2:
new_Name = int(row[0].value)
print("match")
output_file.write(str(new_Name))
output_file.write(",")
output_file.write(",".join(str(c.value) for c in row2[1:]))
output_file.write("\n")
这个解决方案有效,但 运行时间又是荒谬的。理想情况下,我想取 value1(来自第一个 sheet,)然后在另一个 sheet 上对该值执行二进制搜索,然后就像我当前的解决方案一样,如果匹配,则复制整行到一个新文件。那么就
如果有更快的方法来做到这一点,我会洗耳恭听。我在 python 方面不是最出色的,因此我们将不胜感激。
谢谢
你在这里被踢屁股是因为你使用了不合适的数据结构,这需要你使用嵌套循环。
下面的示例使用 sets 来匹配从第一个 sheet 到第二个 sheet 的索引。这 假设 在两个 sheet 上都没有重复项,根据您的问题描述,这看起来很奇怪。一旦我们从两个 sheet 中创建了索引集,我们需要做的就是将这两个集相交以找到 sheet 2.
上的索引集
然后我们有比赛,但我们可以做得更好。如果我们将第二个 sheet 行数据放入以索引为键的字典中,那么我们可以在进行匹配时保留行数据,而不必在与集合相交后去寻找匹配的索引。
我还放入了一个枚举,可能需要也可能不需要它来确定传播sheet 中的哪些行是感兴趣的行。可能不需要。
加载完成后,这应该会在眨眼间执行。如果你开始有内存问题,你可能只想在开始时构建字典而不是列表和字典。
第 1 本书:
第 2 本书:
代码:
import openpyxl
g1 = openpyxl.load_workbook('Book1.xlsx',read_only=True)
grid1 = g1.active
grid1_rows = list(grid1.rows)[1:] # exclude the header
g2 = openpyxl.load_workbook('Book2.xlsx',read_only=True)
grid2 = g2.active
grid2_rows = list(grid2.rows)[1:] # exclude the header
# make a set of the values in Book 1 that we want to search for...
search_items = {int(t[0].value) for t in grid1_rows}
#print(search_items)
# make a dictionary (key-value paring) for the items in the 2nd book, and
# include an enumeration so we can capture the row number
lookup_dict = {int(t[0].value) : (idx, t) for idx,t in enumerate(grid2_rows, start=1)}
#print(lookup_dict)
# now let's intersect the set of search items and key values to get the keys of the matches...
keys = search_items & lookup_dict.keys()
#print(keys)
for key in keys:
idx = lookup_dict.get(key)[0] # the row index, if needed
row_data = lookup_dict.get(key)[1] # the row data
print(f'row {idx} matched value {key} and has data:')
print(f' name: {row_data[1].value:10s} \t qty: {int(row_data[2].value)}')
输出:
row 3 matched value 202 and has data:
name: steak qty: 3
row 1 matched value 455 and has data:
name: dogfood qty: 10
问题:我有两个传播sheet。 Spreadsheet 1 有大约 20,000 行。 Spreadsheet 2 有近 100 万行。当 spreadsheet 1 中一行的值与 spreadsheet 2 中一行的值匹配时,spreadsheet 2 中的整行被写入 excel。题目不是太难,但是行数如此之多,运行时间长得令人难以置信。
第 1 本书示例: |键|值| |------|--------------------| |397241|587727227839578000|
第 2 本书的示例:
ID | a | b | c |
---|---|---|---|
587727227839578000 | 393 | 24 | 0.43 |
我目前的解决方案是:
g1 = openpyxl.load_workbook('path/to/sheet/sheet1.xlsx',read_only=True)
grid1 = g1.active
grid1_rows = list(grid1.rows)
g2 = openpyxl.load_workbook('path/to/sheet2/sheet2.xlsx',read_only=True)
grid2 = g2.active
grid2_rows = list(grid2.rows)
for row in grid1_rows:
value1 = int(row[1].value)
print(value1)
for row2 in grid2_rows:
value2 = int(row2[0].value)
if value1 == value2:
new_Name = int(row[0].value)
print("match")
output_file.write(str(new_Name))
output_file.write(",")
output_file.write(",".join(str(c.value) for c in row2[1:]))
output_file.write("\n")
这个解决方案有效,但 运行时间又是荒谬的。理想情况下,我想取 value1(来自第一个 sheet,)然后在另一个 sheet 上对该值执行二进制搜索,然后就像我当前的解决方案一样,如果匹配,则复制整行到一个新文件。那么就
如果有更快的方法来做到这一点,我会洗耳恭听。我在 python 方面不是最出色的,因此我们将不胜感激。 谢谢
你在这里被踢屁股是因为你使用了不合适的数据结构,这需要你使用嵌套循环。
下面的示例使用 sets 来匹配从第一个 sheet 到第二个 sheet 的索引。这 假设 在两个 sheet 上都没有重复项,根据您的问题描述,这看起来很奇怪。一旦我们从两个 sheet 中创建了索引集,我们需要做的就是将这两个集相交以找到 sheet 2.
上的索引集然后我们有比赛,但我们可以做得更好。如果我们将第二个 sheet 行数据放入以索引为键的字典中,那么我们可以在进行匹配时保留行数据,而不必在与集合相交后去寻找匹配的索引。
我还放入了一个枚举,可能需要也可能不需要它来确定传播sheet 中的哪些行是感兴趣的行。可能不需要。
加载完成后,这应该会在眨眼间执行。如果你开始有内存问题,你可能只想在开始时构建字典而不是列表和字典。
第 1 本书:
第 2 本书:
代码:
import openpyxl
g1 = openpyxl.load_workbook('Book1.xlsx',read_only=True)
grid1 = g1.active
grid1_rows = list(grid1.rows)[1:] # exclude the header
g2 = openpyxl.load_workbook('Book2.xlsx',read_only=True)
grid2 = g2.active
grid2_rows = list(grid2.rows)[1:] # exclude the header
# make a set of the values in Book 1 that we want to search for...
search_items = {int(t[0].value) for t in grid1_rows}
#print(search_items)
# make a dictionary (key-value paring) for the items in the 2nd book, and
# include an enumeration so we can capture the row number
lookup_dict = {int(t[0].value) : (idx, t) for idx,t in enumerate(grid2_rows, start=1)}
#print(lookup_dict)
# now let's intersect the set of search items and key values to get the keys of the matches...
keys = search_items & lookup_dict.keys()
#print(keys)
for key in keys:
idx = lookup_dict.get(key)[0] # the row index, if needed
row_data = lookup_dict.get(key)[1] # the row data
print(f'row {idx} matched value {key} and has data:')
print(f' name: {row_data[1].value:10s} \t qty: {int(row_data[2].value)}')
输出:
row 3 matched value 202 and has data:
name: steak qty: 3
row 1 matched value 455 and has data:
name: dogfood qty: 10