2012-07-20 66 views
1

匹配行我得到每两个文件包含以 “时间” 列,一个与 “ID” 是这样的:减去在python

文件1:

time  id 
11.24 1 
11.26 2 
11.27 3 
11.29 5 
11.30 6 

文件2:

time  id 
11.25 1 
11.26 3 
11.27 4 
11.31 6 
11.32 7 
11.33 8 

我试图做一个python脚本,可以减去相互匹配的id行的时间。这些文件的长度不同。

我试过使用set(id's of file 1) & set(id's of file 2)来获得匹配的id,但现在我卡住了。任何帮助将不胜感激,谢谢。

+1

这个特定情况下的输出应该如何? – eumiro 2012-07-20 10:36:17

回答

2

Python集不支持对元素进行排序。我想将数据存储作为字典

file1 = {1:'11:24', 2:'11:26', ... etc} 
file2 = {1:'11:25', 3:'11:26', ... etc} 

以上(根据您的需要或联合)键的交叉循环做减法(基于时间或基于数学)。

+0

词典不支持排序 – entropy 2012-07-20 23:46:34

+0

@entropy yes但这在这里并不重要,因为循环只能通过键的交集(完全像您在回答中编码的那样)。 – Meitham 2012-07-21 12:49:30

0

这是一个有点老派。看看使用collections模块的默认字典作为更优雅的方法。

这将适用于任何数量的文件,我已经命名为我的f1,f2等。一般的想法是处理每个文件并为每个id建立一个时间值列表。文件处理完成后,遍历字典,按照当前值(通过值列表中的reduce)减去每个值。

from operator import sub 

d = {} 
for fname in ('f1','f2'): 
    for l in open(fname): 
     t, i = l.split() 
     d[i] = d.get(i, []) + [float(t)] 

results = {} 
for k,v in d.items(): 
    results[k] = reduce(sub, v) 

print results 
{'1': -0.009999999999999787, '3': 0.009999999999999787, '2': 11.26, '5': 11.29, '4': 11.27, '7': 11.32, '6': -0.009999999999999787, '8': 11.33} 

更新

如果你想只包括与多个值这些ID:

results = {} 
for k,v in d.items(): 
    if len(v) > 1: 
     results[k] = reduce(sub, v) 
+0

看起来像一个非常好的解决方案。但是,如果我只想保留具有匹配ID的行,该怎么办? – user1540477 2012-07-20 11:25:00

+0

@ user1540477:只需检查最后一个循环中值列表的长度是否大于1。查看更新的答案。 – mhawke 2012-07-22 23:43:43

0

您可以使用此作为基础(而不是把'11 0.24' 为一个浮点数,我想你想适应几小时/分钟或分钟/秒)...你可以使用defaultdict有效地结合并减去匹配键。

只要你可以得到你的数据转换成这样的格式:

f1 = [ 
    [11.24, 1], 
    [11.26, 2], 
    [11.27, 3], 
    [11.29, 5], 
    [11.30, 6] 
] 

f2 = [ 
    [11.25, 1], 
    [11.26, 3], 
    [11.27, 4], 
    [11.31, 6], 
    [11.32, 7], 
    [11.33, 8] 
] 

然后:

from collections import defaultdict 
from itertools import chain 

dd = defaultdict(float) 
for k, v in chain(
    ((b, a) for a, b in f1), 
    ((b, -a) for a, b in f2)): # negate a 

    dd[k] += v 

结果:

{1: -0.009999999999999787, 
2: 11.26, 
3: 0.009999999999999787, 
4: -11.27, 
5: 11.29, 
6: -0.009999999999999787, 
7: -11.32, 
8: -11.33} 

对于比赛只

matches = dict((k, v) for v, k in f1) 
d2 = dict((k, v) for v, k in f2) 

for k, v in matches.items(): 
    try: 
     matches[k] = v - d2[k] 
    except KeyError as e: 
     del matches[k] 

print matches 
# {1: -0.009999999999999787, 3: 0.009999999999999787, 6: -0.009999999999999787} 
+0

似乎是一个非常好的解决方案。但是,如果我只想保留具有匹配ID的行,该怎么办? – user1540477 2012-07-20 11:24:50

+0

@ user1540477更新为只匹配 – 2012-07-20 11:40:39

3

列表内涵可以做的伎俩很容易:

#read these from file if you want to, included in this form for brevity 
F1 = {1: 11.24, 2: 11.26, 3:11.27, 5:11.29, 6:11.30} 
F2 = {1:11.25, 3:11.26, 4:11.27, 6:11.31, 7:11.32, 8:11.33} 

K1 = set(F1.keys()) 
K2 = set(F2.keys()) 

result = dict([ (k, F1[k] - F2[k]) for k in (K1 & K2)]) 
print result 

这将输出:

{1: -0.009999999999999787, 3: 0.009999999999999787, 6: -0.009999999999999787} 

编辑:mhawke指出,最后一行可以读取:

result = {k: F1[k] - F2[k]) for k in (K1 & K2)} 

我忘记了所有关于字典的理解。

+1

+1:很好的解决方案。您还可以在最后一步中使用词典理解:'(k1&K2)}中的结果= {k:F1 [k] - F2 [k]}' – mhawke 2012-07-22 23:58:48

+0

感谢您的支持,将它添加到答案中 – entropy 2012-07-23 09:37:07