我有一个文件,其内容的格式为:
.2323 1
.2327 1
.3432 1
.4543 1
等每个文件中的大约10,000行。 我有一个变量,其值为a = .3344
从文件中我想得到第一列最接近这个变量的行的行号...例如,它应该给出row_num ='3',因为.3432最接近它。
我尝试过在列表中加载第一列元素然后将变量与每个元素进行比较并获取索引号的方法
如果我使用这种方法,这是非常耗费时间并且减慢我的模型......我想要一个非常快速的方法,因为这需要调用最少1000次......
我想要一种开销最小且非常快的方法,任何人都可以告诉我如何快速完成。 由于文件大小最大为100kb,这可以直接完成,无需加载到任何列表中......如果是,如何完成。
任何比上述方法更快的方法都是受欢迎的,但我很想提高速度 - 请帮忙。
def get_list(file, cmp, fout):
ind, _ = min(enumerate(file), key=lambda x: abs(x[1] - cmp))
return fout[ind].rstrip('\n').split(' ')
#root = r'c:\begpython\wavnk'
header = 6
for lst in lists:
save = database_index[lst]
#print save
index, base,abs2, _ , abs1 = save
using_data[index] = save
base = 'C:/begpython/wavnk/'+ base.replace('phone', 'text')
fin, fout = base + '.pm', base + '.mcep'
file = open(fin)
fout = open(fout).readlines()
[next(file) for _ in range(header)]
file = [float(line.partition(' ')[0]) for line in file]
join_cost_index_end[index] = get_list(file, float(abs1), fout)
join_cost_index_strt[index] = get_list(file, float(abs2), fout)
这是我正在使用的代码。将文件复制到列表中。所有请给这个更好的替代品
答案 0 :(得分:3)
文件中的数据是按数字顺序排序的吗?所有的线都长度相同吗?如果没有,最简单的方法是最好的。即,逐行读取文件。一次不需要在内存中存储多行。
def closest(num):
closest_row = None
closest_value = None
for row_num, row in enumerate(file('numbers.txt')):
value = float(row.split()[0])
if closest_value is None or abs(value - num) < abs(closest_value - num):
closest_row = row
closest_row_num = row_num
closest_value = value
return (closest_row_num, closest_row)
print closest(.3344)
(2, '.3432 1\n')
如果行的长度都相同并且数据已经排序,那么有一些优化可以使这个过程变得非常快。所有相同长度的行都可以让您直接搜索特定行(您不能在具有不同长度行的普通文本文件中执行此操作)。然后,这将使您能够进行二分搜索。
二进制搜索比线性搜索快得多。线性搜索平均每次必须读取10,000行10000行文件,而二进制搜索平均只读取log 2 10,000≈ 13 行。 / p>
答案 1 :(得分:3)
基于John Kugelman的回答,这里有一种方法可以对具有固定长度行的文件进行二进制搜索:
class SubscriptableFile(object):
def __init__(self, file):
self._file = file
file.seek(0,0)
self._line_length = len(file.readline())
file.seek(0,2)
self._len = file.tell() / self._line_length
def __len__(self):
return self._len
def __getitem__(self, key):
self._file.seek(key * self._line_length)
s = self._file.readline()
if s:
return float(s.split()[0])
else:
raise KeyError('Line number too large')
此类将文件包装在类似列表的结构中,以便现在可以使用bisect
模块的功能:
def find_row(file, target):
fw = SubscriptableFile(file)
i = bisect.bisect_left(fw, target)
if fw[i + 1] - target < target - fw[i]:
return i + 1
else:
return i
此处file
是一个打开的文件对象,target
是您要查找的数字。该函数返回具有最接近值的行号。
但是,我会注意到,bisect
模块在可用时会尝试使用其二进制搜索的C实现,而且我不确定C实现是否支持这种行为。它可能需要一个真正的列表,而不是“假名单”(如我的SubscriptableFile
)。
答案 2 :(得分:2)
将其加载到列表中,然后使用bisect
。