Perl数据处理

时间:2015-03-16 14:43:46

标签: perl

我的数据如下:

$data = [
    [qw(x y)],
    [qw(x)  ],
    [qw(x z)],
    [qw(z)  ], 
];

我想把它转换成如下所示:

 [ x, x, x, z ]

规则从第一个元素开始,找到前两个元素之间的公共元素,如果找到任何公共元素,则将公共值分配给两个元素,即x。现在选择第二个和第三个元素,找出它们之间是否有任何共同值,然后继续执行,直到到达最后一个元素。如果你在最后两对之间找到共同的值,那么只将它分配给最后一个元素。

2 个答案:

答案 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]};
}