我正在处理2个大文件。主文件有2个字段,例如客户名称,第二个字段是客户ID。我有第二个文件,它是第一个文件的子集,只有客户名称。我希望找到子集文件中存在的名称的客户ID。
第一个文件有3000万行,第二个文件有500万行。
我正在尝试使用字典,但它需要花费大量时间。
你能告诉我一个更好的方法吗?
以下是我的代码中的代码段和我文件中的几行代码。
主文件
#约翰2343245
卡里姆126754
Rob 6543289
维杰2247861
山姆2649860
....
子集第二个文件
他自己
抢
约翰
def extract_info(sub_file,master_file):
sub_fh = open(sub_file,'r',16777216)
sub_inst_list = []
for line in sub_fh:
if line.startswith('#'):
continue
else:
name = line.rstrip()
sub_inst_list.append(name)
sub_fh.close()
out_file = "results.rpt"
outf = open(out_file,'w')
bunchsize = 10000
bunch = []
master_fh = open(master_file,'r',16777216)
for line in master_fh:
if line.startswith('#'):
continue
else:
data = line.split()
name = data[0]
if str(data[1]) == "n/a":
continue
else:
if name in sub_inst_list:
id = str(data[1])
line = "%-80s %-15s\n" % (name, id)
bunch.append(line)
if len(bunch) == bunchsize:
outf.writelines(bunch)
bunch= []
outf.writelines(bunch)
master_fh.close()
outf.close()
更好的方法是将主文件中的所有数据放入数据库,然后根据第二个文件中的键查找值:
import sqlite3
conn = sqlite3.connect(":memory:")
c = conn.cursor()
c.execute("CREATE TABLE data (Name VARCHAR(255), ID INT)")
# fill the DB
with open("master.txt") as f:
for line in f:
c.execute("INSERT INTO data VALUES (?, ?)", line.split())
conn.commit()
# search for data
with open("slave.txt") as f:
for line in f:
print(c.execute("SELECT ID FROM data WHERE Name=:search_name", {"search_name": line.strip()}).fetchall())
conn.close()
另一个可能的解决方案(可能比ForceBru慢,但是编码XD很有趣)是使用线程大幅减少时间:
from queue import Queue
from threading import Thread
q = Queue()
number_of_threads = 3
def get_customer_id():
while True:
customer_name = q.get()
with open('Master.txt', 'r') as f:
for line in f.readlines():
if customer_name.strip() in line:
print(line.strip())
break
q.task_done()
with open('Slave.txt', 'r') as f:
for line in f.readlines():
q.put(line)
for i in range(number_of_threads):
new_thread = Thread(target=get_customer_id)
new_thread.setDaemon(True)
new_thread.start()
print('main thread waiting')
q.join()
print('done')
您可以将线程数增加到100-200,然后让它们离开!这将是计算上非常昂贵的,因为你有最近的迭代次数接近125,000,000,000,000最坏情况。这是相当夸张的,因为break
声明应该削减大量的迭代。如果它在100个线程中运行,那么你可以将数字从break
减少后将其除以100(假设你还没有达到最大CPU使用率,在这种情况下多处理会更好)。尽管用这种方法计算了LOOOOTS。
这基本上就是你的初始脚本正在做的事情,但通过分割和征服来运行它的次数要快很多倍!