对于模糊的问题感到抱歉,我正在努力思考如何更好地说出来!
我有一个看起来有点像这样的CSV文件,只有更大的文件:
550672,1
656372,1
766153,1
550672,2
656372,2
868194,2
766151,2
550672,3
868179,3
868194,3
550672,4
766153,4
第一列中的值是ID号,第二列可以描述为属性(因为缺少更好的词......)。 ID号550672具有属性1,2,3,4。任何人都可以指出我如何开始解决如何生成所有ID号码的字符串?我理想的输出是一个新的csv文件,看起来像:
550672,1;2;3;4
656372,1;2
766153,1;4
等
我非常喜欢Perl宝宝(只有3天大!)所以我真的很欣赏方向,而不是直接的解决方案,我决心学习这些东西,即使它花了我余下的时间!我尽我所能尽力调查它,虽然我认为我已经因为不知道该寻找什么而陷入困境。我能够读入并解析CSV文件(我甚至可以删除重复的值!)但是这真的是我为它丢弃的地方。任何帮助将不胜感激!
答案 0 :(得分:4)
我认为最好是为您提供工作计划而不是一些提示。提示只能带你到目前为止,如果你花时间了解这段代码,它将为你提供良好的学习体验
最好在处理CSV数据时使用Text::CSV
,因为已经为您完成了所有调试
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new;
open my $fh, '<', 'data.txt' or die $!;
my %data;
while (my $line = <$fh>) {
$csv->parse($line) or die "Invalid data line";
my ($key, $val) = $csv->fields;
push @{ $data{$key} }, $val
}
for my $id (sort keys %data) {
printf "%s,%s\n", $id, join ';', @{ $data{$id} };
}
<强>输出强>
550672,1;2;3;4
656372,1;2
766151,2
766153,1;4
868179,3
868194,2;3
答案 1 :(得分:3)
首先是寻求方法而不是解决方案的道具。 正如您可能已经在perl中找到的那样,有多种方法可以做到。
我将采取的方法是;
use strict; # will save you big time in the long run
my %ids # Use a hash table with the id as the key to accumulate the properties
open a file handle on csv or die
while (read another line from the file handle){
split line into ID and property variable # google the split function
append new property to existing properties for this id in the hash table # If it doesn't exist already, it will be created
}
foreach my $key (keys %ids) {
deduplicate properties
print/display/do whatever you need to do with the result
}
这种方法意味着您需要迭代整个集合两次(一次在内存中),因此根据可能存在问题的数据集的大小。 更复杂的方法是使用哈希表的哈希表在初始步骤中执行de duplication,但是根据您希望/需要多快地运行它,这在第一个实例中可能不值得。
退房 this question 有关如何进行重复数据删除的讨论。
答案 2 :(得分:2)
好吧,在perl中将文件作为stdin打开,假设每行有两列,然后使用左列作为散列标识符迭代所有行,并将右列收集到由散列键指向的数组中。在输入文件的末尾,您将获得数组的哈希值,因此迭代它,打印哈希键并分配以“;”分隔的数组元素或者你想要的任何其他标志。
然后你去
dtpwmbp:~ pwadas$ cat input.txt
550672,1
656372,1
766153,1
550672,2
656372,2
868194,2
766151,2
550672,3
868179,3
868194,3
550672,4
766153,4
dtpwmbp:~ pwadas$ cat bb2.pl
#!/opt/local/bin/perl
my %hash;
while (<>)
{
chomp;
my($key, $value) = split /,/;
push @{$hash{$key}} , $value ;
}
foreach my $key (sort keys %hash)
{
print $key . "," . join(";", @{$hash{$key}} ) . "\n" ;
}
dtpwmbp:~ pwadas$ cat input.txt | perl -f bb2.pl
550672,1;2;3;4
656372,1;2
766151,2
766153,1;4
868179,3
868194,2;3
dtpwmbp:~ pwadas$
答案 3 :(得分:2)
perl -F"," -ane 'chomp($F[1]);$X{$F[0]}=$X{$F[0]}.";".$F[1];if(eof){for(keys %X){$X{$_}=~s/;//;print $_.",".$X{$_}."\n"}}'
答案 4 :(得分:1)
另一种(不是perl)方式,它更短,更优雅:
#!/opt/local/bin/gawk -f
BEGIN {FS=OFS=",";}
NF > 0 { IDs[$1]=IDs[$1] ";" $2; }
END { for (i in IDs) print i, substr(IDs[i], 2); }
第一行(在指定解释器之后)将输入FIELD SEPARATOR和OUTPUT FIELD SEPARATOR设置为逗号。第二行检查我们有超过零个字段,如果你这样做,则ID($ 1)数字为密钥,$ 2为数值。你为所有行都这样做。
END语句将以未指定的顺序打印出这些对。如果要对它们进行排序,则必须选择asorti
gnu awk函数或将此代码段的输出与管道连接到sort -t, -k1n,1n
。