如何在 Perl 中将文件读入数组但正确处理重复项?
How do I read a file into an array in Perl but correctly handle duplicates?
如何将文件读入数组,但正确处理重复项?
我有一个包含两列的文件,一个名称和一个数字。最终名称会重复,数字可能不同也可能不同。
Rita,13
Sue,11
Bob,01
Too,05
Rita,13
Sue,07
Bob,02
Too,05
我需要将这些行读入一个数组,这不是问题,但以某种方式重新填充它们,以便任何重复的名称都将其值推送到正确的行,这比较棘手。至少对我来说。
所以上面应该创建类似
的东西
Rita,13,13
Sue,11,07
Bob,01,02
Too,05,05
大约有 3000 个名称和大约 600,000 行要处理。
(想法是突出显示哪些名称是稳定的,哪些名称具有变化的值)。
速度并不重要。这将是 运行 大约每周一次。
因为每一行最终都会有多个条目,而每行的第二个条目并不重要(我只需要阅读它并将其填充到新列表),我想我不需要在这里使用散列,我应该只用某种形式的 if 存在(或不存在)遍历输入文件。我是对的还是散列会有好处?
我在 Windows 上使用 Strawberry Perl V5.32.1。
编辑 - 感谢样品,一切都很好。
由于输出发生变化,输入文件现在有必须保留的额外列。
所以现在看起来像
12,Rita,1,4,13
2,Sue,0,1,11
5,Bob,12,5,01
7,Too,1,4,05
12,Rita,1,4,13
2,Sue,0,1,07
5,Bob,12,5,02
7,Too,1,4,05
输出类似,因为只有最后一列会改变
12,Rita,1,4,13,13
2,Sue,0,1,11,07
5,Bob,12,5,01,02
7,Too,1,4,05,05
额外的列不会改变,但必须存在。使用数组并提取第 2 和第 5 列来创建它,或者更改前 4 列的分隔符以使第一列成为唯一键是否仍然有意义?这感觉很脏,但可以工作...
单线
perl -F, -lane '$h{ $F[0] } .= ",$F[1]"; END {print $_, $h{$_} for keys %h}' -- file
作为脚本:
#!/usr/bin/perl
use warnings;
use strict;
my %h;
while (<>) {
chomp;
my ($name, $number) = split /,/;
$h{$name} .= ",$number";
}
for my $name (keys %h) {
print $name, $h{$name}, "\n";
}
使用以 用户名 为键的散列和 id 存储在一个数组中使这个任务很容易实现。
请调查以下代码段。
use warnings;
use feature 'say';
my $data;
while( <DATA> ) {
chomp;
my($name,$id) = split /,/;
push @{$data->{$name}}, $id;
}
say join(',',$_,@{$data->{$_}}) for sort keys %$data;
exit 0;
__DATA__
Rita,13
Sue,11
Bob,01
Too,05
Rita,13
Sue,07
Bob,02
Too,05
输出
Bob,01,02
Rita,13,13
Sue,11,07
Too,05,05
您的问题的基本解决方案已给出,但忽略了两件事:1) 名称的原始顺序不能用散列保留,2) 如果任何一行有多个值,则丢弃附加值.所以我想到了这个:
use strict;
use warnings;
use feature 'say';
my %d;
my @keys;
while (<DATA>) {
chomp;
my ($key, @val) = split /,/, $_; # use array to store multiple values
push @keys, $key if not defined $d{$key}; # preserve original order of lines
push @{ $d{$key} }, @val; # store values
}
say join ",", $_, @{ $d{$_} } for @keys; # print lines in original order
__DATA__
Rita,13
Sue,11
Bob,01,23
Too,05
Rita,13
Sue,07
Bob,02
Too,05
输出:
Rita,13,13
Sue,11,07
Bob,01,23,02
Too,05,05
如何将文件读入数组,但正确处理重复项?
我有一个包含两列的文件,一个名称和一个数字。最终名称会重复,数字可能不同也可能不同。
Rita,13
Sue,11
Bob,01
Too,05
Rita,13
Sue,07
Bob,02
Too,05
我需要将这些行读入一个数组,这不是问题,但以某种方式重新填充它们,以便任何重复的名称都将其值推送到正确的行,这比较棘手。至少对我来说。
所以上面应该创建类似
的东西Rita,13,13
Sue,11,07
Bob,01,02
Too,05,05
大约有 3000 个名称和大约 600,000 行要处理。 (想法是突出显示哪些名称是稳定的,哪些名称具有变化的值)。
速度并不重要。这将是 运行 大约每周一次。
因为每一行最终都会有多个条目,而每行的第二个条目并不重要(我只需要阅读它并将其填充到新列表),我想我不需要在这里使用散列,我应该只用某种形式的 if 存在(或不存在)遍历输入文件。我是对的还是散列会有好处?
我在 Windows 上使用 Strawberry Perl V5.32.1。
编辑 - 感谢样品,一切都很好。
由于输出发生变化,输入文件现在有必须保留的额外列。
所以现在看起来像
12,Rita,1,4,13
2,Sue,0,1,11
5,Bob,12,5,01
7,Too,1,4,05
12,Rita,1,4,13
2,Sue,0,1,07
5,Bob,12,5,02
7,Too,1,4,05
输出类似,因为只有最后一列会改变
12,Rita,1,4,13,13
2,Sue,0,1,11,07
5,Bob,12,5,01,02
7,Too,1,4,05,05
额外的列不会改变,但必须存在。使用数组并提取第 2 和第 5 列来创建它,或者更改前 4 列的分隔符以使第一列成为唯一键是否仍然有意义?这感觉很脏,但可以工作...
单线
perl -F, -lane '$h{ $F[0] } .= ",$F[1]"; END {print $_, $h{$_} for keys %h}' -- file
作为脚本:
#!/usr/bin/perl
use warnings;
use strict;
my %h;
while (<>) {
chomp;
my ($name, $number) = split /,/;
$h{$name} .= ",$number";
}
for my $name (keys %h) {
print $name, $h{$name}, "\n";
}
使用以 用户名 为键的散列和 id 存储在一个数组中使这个任务很容易实现。
请调查以下代码段。
use warnings;
use feature 'say';
my $data;
while( <DATA> ) {
chomp;
my($name,$id) = split /,/;
push @{$data->{$name}}, $id;
}
say join(',',$_,@{$data->{$_}}) for sort keys %$data;
exit 0;
__DATA__
Rita,13
Sue,11
Bob,01
Too,05
Rita,13
Sue,07
Bob,02
Too,05
输出
Bob,01,02
Rita,13,13
Sue,11,07
Too,05,05
您的问题的基本解决方案已给出,但忽略了两件事:1) 名称的原始顺序不能用散列保留,2) 如果任何一行有多个值,则丢弃附加值.所以我想到了这个:
use strict;
use warnings;
use feature 'say';
my %d;
my @keys;
while (<DATA>) {
chomp;
my ($key, @val) = split /,/, $_; # use array to store multiple values
push @keys, $key if not defined $d{$key}; # preserve original order of lines
push @{ $d{$key} }, @val; # store values
}
say join ",", $_, @{ $d{$_} } for @keys; # print lines in original order
__DATA__
Rita,13
Sue,11
Bob,01,23
Too,05
Rita,13
Sue,07
Bob,02
Too,05
输出:
Rita,13,13
Sue,11,07
Bob,01,23,02
Too,05,05