我的数据如下:
$data = [
[qw(x y)],
[qw(x) ],
[qw(x z)],
[qw(z) ],
];
我想把它转换成如下所示:
[ x, x, x, z ]
规则从第一个元素开始,找到前两个元素之间的公共元素,如果找到任何公共元素,则将公共值分配给两个元素,即x。现在选择第二个和第三个元素,找出它们之间是否有任何共同值,然后继续执行,直到到达最后一个元素。如果你在最后两对之间找到共同的值,那么只将它分配给最后一个元素。
答案 0 :(得分:0)
听起来你想要计算某些数据点的交集点? 我会做这样的事情:
#!/usr/bin/env perl
use strict; use warnings;
use autodie;
use Data::Dumper;
my @data = (
[qw(x y)],
[qw(x) ],
[qw(x z)],
[qw(z) ],
);
sub intersect {
my ($a, $b) = @_;
my $union = {};
my $isect = {};
foreach my $e (@$a, @$b) {
$union->{$e}++ && $isect->{$e}++;
}
return keys %$isect;
}
my @result = ();
for my $i (0..$#data - 1) {
my @intersection = intersect($data[$i], $data[$i+1]);
if (scalar @intersection) {
my $isect = shift @intersection;
if ($i == 0) {
push @result, $isect;
}
push @result, $isect;
}
else {
die sprintf("Data points do not intersect at position %d", $i+1);
}
}
print Dumper \@result;
运行此脚本会给我以下输出:
$ ./intersection.pl
$VAR1 = [
'x',
'x',
'x',
'z'
];
希望这有帮助。
CPAN上的intersect
包中还提供了另一种Array::Utils
方法。
答案 1 :(得分:0)
使用Array::Utils
模块中的intersect
函数可以轻松完成此操作。它可能需要安装,因为它不是核心模块。
我不确定我的说明是否正确。您想要在前两个列表中添加两次之间的公共元素。是对的吗?如果在任何一对列表之间有多个公共项目,则不会说明会发生什么。这个解决方案只是增加了第一个。
use strict;
use warnings;
use Array::Utils 'intersect';
my $data = [ ['x', 'y'], ['x'], ['x', 'z'], ['z'] ];
my @result;
for my $i ( 1 .. $#$data ) {
my @pair = @{$data}[$i-1, $i];
my @common = intersect(@{$pair[0]}, @{$pair[1]});
push @result, $common[0];
push @result, $common[0] if $i == 1;
}
printf "[ %s ]\n", join ', ', @result;
<强>输出强>
[ x, x, x, z ]
<强>更新强>
如果安装模块有问题,那么您只需将此子例程定义复制到代码末尾,然后删除use Array::Utils
语句。
sub intersect(\@\@) {
my %e = map { $_ => undef } @{$_[0]};
return grep { exists( $e{$_} ) } @{$_[1]};
}