我的表格的每一行都有一个大文件
a b c
我想删除所有不存在其他行的行,例如
b d e
或d a e
abs(c - e) < 10
。
a
,b
,c
,d
,e
都是整数。
例如,如果输入为:
0 1 10
1 2 20
2 3 25
0 1 15
1 4 40
然后输出应该是
1 2 20
2 3 25
0 1 15
是否有可能在线性时间之外做这件事?
一个想法是创建两个排序列表的词典。一个用于与第一列值关联的第三列值。另一个用于与第二列值关联的第三列值。然后当你看到一个b c时,在第二个字典中使用键a获得的排序列表中查找c,然后使用第一个字典中的键b获得排序列表中的c。
答案 0 :(得分:3)
我不知道这是否可以在线性时间内完成。如果输入中有n个三元组,则在O(n·log n)时间内直接进行。以下是一种方法的草图,以一种不一定是优选的实现形式:
制作一系列标记M,最初全部清除。
创建一个数组并复制输入,首先在中间元素上排序,然后在中间元素相等时由第三个元素排序。 (到目前为止,时间是O(n·log n)。)
对于每个不同的中间值,使用key = third元素创建BST(二叉搜索树)。 (时间再次为O(n·log n)。)
使用中间值键入哈希表,数据指向适当的BST。也就是说,给定中间值y和第三个元素z,在时间O(1)中,我们可以得到中间值为y的三元组的BST;从那时起,O(log n)可以找到最接近z的第三元素值的三元组。
对于每个三元组t =(x,y,z)依次,如果尚未设置标记,则使用哈希表查找对应于x的BST(如果有)。在那个BST中,找到最接近z的第三个元素的三元组u。如果差值小于10,则设置t和u的标记。 (时间再次为O(n·log n)。)
重复步骤2-5,但BST基于第一个元素值而不是中间值,并在步骤5中基于y而不是x进行查找。 (虽然匹配关系是对称的,因此我们可以在步骤5中的每个周期设置两个标记,但是一些符合条件的三元组可能最终没有标记;即,它们处于公差范围内,但比找到的最近匹配范围更远。可以在步骤5中标记所有符合条件的三元组,但这会将最坏情况时间从O(n·log n)增加到O(n²·log n)。)
对于设置的每个标记,输出相应的三元组。
总时间:O(n·log n)。同时可以在不构建BST的情况下实现,而是在排序数组的子范围内使用二进制搜索。
编辑:在python中,可以使用 bisect 构建可用的结构,如下面ipython解释器会话的摘录所示。 (可能有更有效的方法来执行这些步骤。)字典h
中的每个数据项都是适合使用bisect
进行搜索的数组。
In [1]: from itertools import groupby
In [2]: a=[(0,1,10), (1,2,20), (2,3,25), (0,1,15), (1,4,40), (1,4,33), (3,3,17), (2,1,19)]
In [3]: b=sorted((e[1],e[2],i) for i,e in enumerate(a)); print b
[(1, 10, 0), (1, 15, 3), (1, 19, 7), (2, 20, 1), (3, 17, 6), (3, 25, 2), (4, 33, 5), (4, 40, 4)]
In [4]: h={k:list(g) for k,g in groupby(b,lambda x: x[0])}; h
Out[4]:
{1: [(1, 10, 0), (1, 15, 3), (1, 19, 7)],
2: [(2, 20, 1)],
3: [(3, 17, 6), (3, 25, 2)],
4: [(4, 33, 5), (4, 40, 4)]}
答案 1 :(得分:1)
lines = """0 1 10
1 2 20
2 3 25
0 1 15
1 4 40"""
Adata = {}
Bdata = {}
for line in lines.split('\n'):
a,b,c = line.split(' ')[:3]
vals = map(int,[a,b,c])
if b in Adata:
Adata[b].append(vals)
else:
Adata[b] = [vals]
if a in Bdata:
Bdata[a].append(vals)
else:
Bdata[a] = [vals]
def case1(a,b,c):
if a in Adata:
for val in Adata[a]:
if abs(int(c)-val[2]) < 10:
return True
return False
def case2(a,b,c):
if b in Bdata:
for val in Bdata[b]:
if abs(int(c)-val[2]) < 10:
return True
return False
out = []
for line in lines.split('\n'):
a,b,c = line.split(' ')[:3]
if case1(a,b,c) or case2(a,b,c):
out.append(line)
for line in out:
print line
答案 2 :(得分:0)
我认为您正在寻找的是
set lines
for line in infile:
if line not in lines:
lines.add(line)
outfile.write(line)