合并记录
Merge records in one
我有一个包含很多类型记录的文件:
|1|a|b|c|||||||
|1||||aa|bb|cc||||
|1|||||||aaa|bbb|ccc|
|2|fd|ef|gf|||||||
|1||||zz|yy|dd||||
我需要合并第一个字段中具有相同值的记录,理想情况下它看起来像这样(假设最后一条记录是最新的):
|1|a|b|c|zz|yy|dd|aaa|bbb|ccc|
|2|fd|ef|gf|||||||
我一直在思考最好的方法。我考虑过使用第一个字段作为主键将所有内容放入数据库 table 中,我也一直在使用 perl 研究哈希...但听起来没有什么理想的。想法? perl 或 python 中的某些东西会很棒,但我对几乎所有我可以在 unix 上 运行 开放的东西都持开放态度。
谢谢!
my %merged_rows;
while (<>) {
chomp;
my @fields = split(/\|/, $_, -1);
my $id = $fields[1];
my $merged_row = $merged_rows{$id} ||= [];
$merged_row->[$_] = $fields[$_]
for grep { length($fields[$_]) || $_ > $#$merged_row } 0..$#fields;
}
for my $id ( sort { $a <=> $b } keys(%merged_rows) ) {
print(join('|', @{ $merged_rows{$id} }), "\n");
}
如果键都是小数字,您可以通过使用数组而不是散列来保存合并的行来获得小幅速度提升。
- 当没有限制时,
split
删除空尾随字段,因此 |1|a|b|c|||||||
与 |1|a|b|c
相同。
$z = $x ||= $y;
等同于 $x ||= $y; $z = $x;
$x ||= $y;
与$x = $x || $y;
基本相同;如果 LHS 为假,它将 RHS 分配给 LHS。在上下文中,如果这是我们第一次遇到 $id
,它会 $merged_rows{$id} = [];
。
[]
创建一个空数组和 returns 对它的引用。
这是 python 中的脚本。
仅当该部分按照行进入的顺序不为空时才会覆盖。
from collections import defaultdict
def merge_lines():
with open('data.txt', 'r') as file:
with open('output.txt', 'w') as file_out:
output_dict = defaultdict(list)
for line in file:
split_line = line.split('|')
# Remove first empty string
del split_line[0]
# If we havn't seen this record before then add it to dictionary
if split_line[0] not in output_dict:
output_dict[split_line[0]] = split_line
else:
# If we have seen it then update the sections providing
# they are not emptystring ('')
for index, val in enumerate(split_line):
if val != '':
output_dict[split_line[0]][index] = val
# Join sections back together and write lines to file
for line_values in output_dict.values():
file_out.write('|' + '|'.join(line_values))
if __name__ == "__main__":
merge_lines()
def update_col(l1,l2):
for i,v in enumerate(l2):
if not v:
continue
l1[i] = v
out = []
for l in open('rec.txt'):
l = l.strip().split('|')
for r in out:
if r[1] == l[1]:
update_col(r,l)
break
else:
out.append(l)
for l in out:
print '|'.join(l)
输出
|1|a|b|c|zz|yy|dd|aaa|bbb|ccc|
|2|fd|ef|gf|||||||
我有一个包含很多类型记录的文件:
|1|a|b|c|||||||
|1||||aa|bb|cc||||
|1|||||||aaa|bbb|ccc|
|2|fd|ef|gf|||||||
|1||||zz|yy|dd||||
我需要合并第一个字段中具有相同值的记录,理想情况下它看起来像这样(假设最后一条记录是最新的):
|1|a|b|c|zz|yy|dd|aaa|bbb|ccc|
|2|fd|ef|gf|||||||
我一直在思考最好的方法。我考虑过使用第一个字段作为主键将所有内容放入数据库 table 中,我也一直在使用 perl 研究哈希...但听起来没有什么理想的。想法? perl 或 python 中的某些东西会很棒,但我对几乎所有我可以在 unix 上 运行 开放的东西都持开放态度。
谢谢!
my %merged_rows;
while (<>) {
chomp;
my @fields = split(/\|/, $_, -1);
my $id = $fields[1];
my $merged_row = $merged_rows{$id} ||= [];
$merged_row->[$_] = $fields[$_]
for grep { length($fields[$_]) || $_ > $#$merged_row } 0..$#fields;
}
for my $id ( sort { $a <=> $b } keys(%merged_rows) ) {
print(join('|', @{ $merged_rows{$id} }), "\n");
}
如果键都是小数字,您可以通过使用数组而不是散列来保存合并的行来获得小幅速度提升。
- 当没有限制时,
split
删除空尾随字段,因此|1|a|b|c|||||||
与|1|a|b|c
相同。 $z = $x ||= $y;
等同于$x ||= $y; $z = $x;
$x ||= $y;
与$x = $x || $y;
基本相同;如果 LHS 为假,它将 RHS 分配给 LHS。在上下文中,如果这是我们第一次遇到$id
,它会$merged_rows{$id} = [];
。[]
创建一个空数组和 returns 对它的引用。
这是 python 中的脚本。
仅当该部分按照行进入的顺序不为空时才会覆盖。
from collections import defaultdict
def merge_lines():
with open('data.txt', 'r') as file:
with open('output.txt', 'w') as file_out:
output_dict = defaultdict(list)
for line in file:
split_line = line.split('|')
# Remove first empty string
del split_line[0]
# If we havn't seen this record before then add it to dictionary
if split_line[0] not in output_dict:
output_dict[split_line[0]] = split_line
else:
# If we have seen it then update the sections providing
# they are not emptystring ('')
for index, val in enumerate(split_line):
if val != '':
output_dict[split_line[0]][index] = val
# Join sections back together and write lines to file
for line_values in output_dict.values():
file_out.write('|' + '|'.join(line_values))
if __name__ == "__main__":
merge_lines()
def update_col(l1,l2):
for i,v in enumerate(l2):
if not v:
continue
l1[i] = v
out = []
for l in open('rec.txt'):
l = l.strip().split('|')
for r in out:
if r[1] == l[1]:
update_col(r,l)
break
else:
out.append(l)
for l in out:
print '|'.join(l)
输出
|1|a|b|c|zz|yy|dd|aaa|bbb|ccc|
|2|fd|ef|gf|||||||