我有一个大的制表符分隔文件,其中包含重复的产品,但颜色和数量不同。我正在尝试基于密钥合并数据,以便最终得到一个产品,并且用分隔符(在这种情况下为逗号)分隔的组合颜色和数量。
我使用Text::CSV
模块以便我有更好的控制权,因为它允许我输出具有不同分隔符的文件(从分号到管道)。
我的问题是,如何正确合并数据?我不希望它只是简单地组合颜色和数量,但也删除重复的值。所以我在考虑Id
/ Amount
和Id
/ Colour
的关键/值。但是Id
并不是唯一的,所以我该怎么做?我是创建数组还是使用哈希?
以下是一些示例源数据,其中制表符分隔符由分号;
替换。请注意,标记的行没有Color,因此空值不会合并到结果中。
Cat_id;Cat_name;Id;Name;Amount;Colour;Bla;
101;Fruits;50020;Strawberry;500;Red;1;
101;Fruits;50020;Strawberry;1000;Red;1;
201;Vegetables;60090;Tomato;50;Green;1;
201;Vegetables;60080;Onion;1;Purple;1;
201;Vegetables;60090;Tomato;100;Red;1;
201;Vegetables;60010;Carrot;100;Purple;1;
201;Vegetables;60050;Broccoli;500;Green;1;
201;Vegetables;60050;Broccoli;1000;Green;1;
201;Vegetables;60090;Tomato;500;Yellow;1;
101;Fruits;50060;Apple;500;Green;1;
101;Fruits;50010;Grape;500;Red;1;
201;Vegetables;60010;Carrot;500;White;1;
201;Vegetables;60050;Broccoli;2000;Green;1;
201;Vegetables;60090;Tomato;1000;Red;1;
101;Fruits;50020;Strawberry;100;Red;1;
101;Fruits;50060;Apple;1000;Red;1;
201;Vegetables;60010;Carrot;250;Yellow;1;
101;Fruits;50010;Grape;100;White;1;
101;Fruits;50030;Banana;500;Yellow;1;
201;Vegetables;60010;Carrot;1000;Yellow;1;
101;Fruits;50030;Banana;1000;Green;1;
101;Fruits;50020;Strawberry;200;Red;1;
101;Fruits;50010;Grape;200;White;1;
201;Vegetables;60010;Carrot;50;Orange;1;
201;Vegetables;60080;Onion;2;White;1;
我想要的结果是:
101;Fruits;50010;Grape;100,500,200;Red,White;1;
201;Vegetables;60090;Tomato;50,500,1000,10;Yellow,Green,Red;1;
101;Fruits;50060;Apple;500,1000;Red,Green;1;
201;Vegetables;60010;Carrot;250,50,500,1000,100;Orange,Yellow,White,Purple;1;
201;Vegetables;60050;Broccoli;1000,500,2000;Green;1;
101;Fruits;50020;Strawberry;100,1000,200,500;Red;1;
101;Fruits;50030;Banana;500,1000;Yellow,Green;1;
201;Vegetables;60080;Onion;2,1;White,Purple;1;
到目前为止,这是我的脚本。它没有完成(并且没有工作),因为我不确定如何继续。我不认为这可以正常工作,因为我试图使用不同颜色的相同密钥。
use strict;
use warnings;
use Text::CSV;
use List::MoreUtils 'uniq';
my $inputfile = shift || die "Give input and output names!\n";
my $outputfile = shift || die "Give output name!\n";
open my $infile, '<', $inputfile or die "Sourcefile in use / not found :$!\n";
open my $outfile, '>', $outputfile or die "Outputfile in use :$!\n";
binmode($outfile, ":encoding(utf8)");
my $csv_in = Text::CSV->new({binary => 1,sep_char => ";",eol => $/});
my $csv_out = Text::CSV->new({binary => 1,sep_char => "|",always_quote => 1,eol => $/}); #,quote_null => 0 #
my %data;
while (my $elements = $csv_in->getline($infile)){
my $id = $elements->[2];
push @{ $data{$id} }, \@elements;
}
for my $id ( sort keys %data ){
my $set = $data{$id};
my @elements = @{ $set->[0] };
$elements[4] = join ',', uniq map { $_->[4] } @$set;
$elements[5] = join ',', uniq map { $_->[5] } @$set;
$csv_in->combine(@$elements);
$csv_out->print($outfile, $elements);
}
编辑:我使用data :: dumper进行测试,但最终还是希望将其写入文件。
答案 0 :(得分:0)
哈希处理唯一键。正如你所猜测的那样 - 如果你覆盖了#39;颜色,然后...旧值被替换。
但是哈希可以包含数组(ref)s。所以你可以这样做:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $id = 50010;
my %hash;
$hash{$id}{'colour'} = [ "red", "green", "blue" ];
push( @{ $hash{$id}{'colour'} }, "orange" );
print Dumper \%hash;
如果你没有任何重复的颜色,这将工作。 (例如,只有一行白葡萄与该ID。)。
您可能需要使用join
进行后处理,才能将数组转换为字符串。
或者作为替代方案,您可以将颜色连接到现有颜色:
if ( defined $hash->{$id}->{colour} ) {
$hash->{$id}->{colour} .= ",$colour";
}
我还要注意 - 我不清楚你在$elements->[10]
做了什么,因为没有10列。我还强烈建议不使用变量的通用名称 - 比如%hash
- 因为它只是一个坏习惯。模糊的变量名称是糟糕的风格,虽然它在很大程度上是学术性的,当你查看一小部分代码时,养成习惯清楚地表达你对特定变量的期望是什么。 (如果不清楚数据类型,尤其如此)
答案 1 :(得分:0)
我没有时间撰写适当的评论,但这个程序似乎可以满足您的需求。它使用List::MoreUtils
模块中的uniq
函数。它不是核心模块,因此可能需要安装。我相信Amounts和Colors在组合字段中出现的顺序并不重要吗?
use strict;
use warnings;
use List::MoreUtils 'uniq';
print scalar <DATA>;
my %data;
while (<DATA>) {
chomp;
my @fields = split /;/;
my $id = $fields[2];
push @{ $data{$id} }, \@fields;
}
for my $id ( sort keys %data ) {
my $set = $data{$id};
my @fields = @{ $set->[0] };
$fields[4] = join ',', uniq map { $_->[4] } @$set;
$fields[5] = join ',', uniq map { $_->[5] } @$set;
print join(';', @fields, ''), "\n";
}
__DATA__
Cat_id;Cat_name;Id;Name;Amount;Colour;Bla;
101;Fruits;50020;Strawberry;500;Red;1;
101;Fruits;50020;Strawberry;1000;Red;1;
201;Vegetables;60090;Tomato;50;Green;1;
201;Vegetables;60080;Onion;1;Purple;1;
201;Vegetables;60090;Tomato;100;Red;1;
201;Vegetables;60010;Carrot;100;Purple;1;
201;Vegetables;60050;Broccoli;500;Green;1;
201;Vegetables;60050;Broccoli;1000;Green;1;
201;Vegetables;60090;Tomato;500;Yellow;1;
101;Fruits;50060;Apple;500;Green;1;
101;Fruits;50010;Grape;500;Red;1;
201;Vegetables;60010;Carrot;500;White;1;
201;Vegetables;60050;Broccoli;2000;Green;1;
201;Vegetables;60090;Tomato;1000;Red;1;
101;Fruits;50020;Strawberry;100;Red;1;
101;Fruits;50060;Apple;1000;Red;1;
201;Vegetables;60010;Carrot;250;Yellow;1;
101;Fruits;50010;Grape;100;White;1;
101;Fruits;50030;Banana;500;Yellow;1;
201;Vegetables;60010;Carrot;1000;Yellow;1;
101;Fruits;50030;Banana;1000;Green;1;
101;Fruits;50020;Strawberry;200;Red;1;
101;Fruits;50010;Grape;200;White;1;
201;Vegetables;60010;Carrot;50;Orange;1;
201;Vegetables;60080;Onion;2;White;1;
<强>输出强>
Cat_id;Cat_name;Id;Name;Amount;Colour;Bla;
101;Fruits;50010;Grape;500,100,200;Red,White;1;
101;Fruits;50020;Strawberry;500,1000,100,200;Red;1;
101;Fruits;50030;Banana;500,1000;Yellow,Green;1;
101;Fruits;50060;Apple;500,1000;Green,Red;1;
201;Vegetables;60010;Carrot;100,500,250,1000,50;Purple,White,Yellow,Orange;1;
201;Vegetables;60050;Broccoli;500,1000,2000;Green;1;
201;Vegetables;60080;Onion;1,2;Purple,White;1;
201;Vegetables;60090;Tomato;50,100,500,1000;Green,Red,Yellow;1;