我有两个文件,行数如下:
file1 - 110433003
file2 - 4838810
我需要找到它们之间的常用短语。每一行的形式如下:
p1 ||| p2 ||| .......
file1的p1可以是file2中的p2。不幸的是,我写的代码花了太长时间才做到这一点。
import sys
import os
if(len(sys.argv)<2):
print 'python CommonPhrases.py enFr hrEn commonFile'
sys.exit()
enFr = open(sys.argv[1],'r')
hrEn = open(sys.argv[2],'r')
common = open(sys.argv[3],'w')
sethrEn = set([])
setenFr= set([])
for line in hrEn:
englishPhrase = line.split(' ||| ')[1]
sethrEn.add(englishPhrase)
for line in enFr:
englishPhrase = line.split(' ||| ')[0]
if(englishPhrase in sethrEn):
common.write(englishPhrase+'\n')
有更快的方法吗?
谢谢
答案 0 :(得分:0)
你肯定需要这样的东西。看起来你将花费大部分时间来搜索比赛。
每当我发现自己试图让python更快时,我就会切换到pypy。 (http://pypy.org/) 它非常容易设置(只需下载二进制文件,将它放在你的路径中并将#!/ usr / bin / env python更改为#!/ usr / bin / env pypy)并提供5-10x范围内的加速比这样的任务。
有关使用PyTrie的参考实现,请参阅下文。
#!/usr/bin/env pypy
import sys
import os
sys.path.append('/usr/local/lib/python2.7/dist-packages/PyTrie-0.1-py2.7.egg/')
from pytrie import SortedStringTrie as trie
if(len(sys.argv)<2):
print 'python CommonPhrases.py enFr hrEn commonFile'
sys.exit()
enFr = open(sys.argv[1],'r')
hrEn = open(sys.argv[2],'r')
common = open(sys.argv[3],'w')
sethrEn = trie()
for line in hrEn:
englishPhrase = line.strip().split(' ||| ')[1]
sethrEn[englishPhrase] = None
for line in enFr:
englishPhrase = line.strip().split(' ||| ')[0]
if(englishPhrase in sethrEn):
common.write(englishPhrase+'\n')
请注意,它需要最少的更改(4行),您需要安装PyTrie 0.1。在我的ubuntu系统上,“sudo easy_install PyTrie”就行了。
希望有所帮助。
答案 1 :(得分:0)
这听起来像树问题。也许这个想法可以帮助你。
使用树可以帮助找到常用词。我认为基于创建树的想法可以有两种解决方案。
树实现后,需要存储一个文件的每个单词(只有一个文件)。然后,开始读取第二个文件并搜索树中该文件上的每个单词。
这个解决方案当然有一些问题。在存储大量单词(或行)的内存中存储树可能需要大量的MB RAM。
让我们假设您设法使用固定数量的RAM来存储数据,因此,只计算数据本身(行的字符)。在最坏的情况下,您将需要255 ^ N个字节,其中N是最长行的长度(假设您使用almos每个N扩展的单词组合)。因此,存储长度为10的单词的每个组合,您将需要1.16252367019e + 24字节的RAM。那是很多。请记住,这个解决方案(据我所知)是“快速的”,但需要比你能找到的更多的RAM。
所以,其他解决方案,非常非常慢,是读取一行文件A,然后将其与文件B的每一行进行比较。它几乎不需要RAM,但需要太多时间,也许你不会能够真正等待它。
所以,也许另一个解决方案就是解决问题。
你说你有一个行列表,我们不知道它们是按字母顺序排序的。所以,也许你可以开始阅读文件A,并创建新文件。例如,每个新文件将存储'A'起始行,其他以'B'开头的行等等。然后,对文件B执行相同操作,并将两个文件作为'A'开始行,一个用于原始A文件,另一个用于原始B文件。然后,将它们与树进行比较。
在最好的情况下,线条将被平分,让你在内存中使用树。在最坏的情况下,您将只完成一个文件,与起始A文件相同,因为可能所有行都以'A'开头。
所以,也许,你可以实现一种方法来分割更多的文件,如果它们仍然太大,首先是行上的第一个字符。然后,'A'起始行,将它们划分为'AA','AB','AC'等,当然,删除以前的分割文件,直到你得到足够小的文件,使用更好的方法来搜索相同的线(可能在内存中使用树)。
这个解决方案也可能需要很长时间,但可能不会像低ram选项那么长,而且也不需要太多ram来工作。
这些是我现在能想到的解决方案。也许他们的工作,也许不是。