在Perl中扩展列表引用

时间:2015-09-17 20:33:12

标签: perl

我在Perl中有一个列表,我正在尝试“扩展”它包含的任何列表。

例如:

my @l = (
  'foo',
  ['A', 'B'],
  'bar',
  ['X', 'Y', 'Z'],
  'baz',
);

我想扩展列表以获取此信息:

my @want = (
  [qw/ foo A bar X baz /],
  [qw/ foo A bar Y baz /],
  [qw/ foo A bar Z baz /],
  [qw/ foo B bar X baz /],
  [qw/ foo B bar Y baz /],
  [qw/ foo B bar Z baz /],
);

我想出了这个,它有效,但很难看,并且没有产生明智的有序阵列:

my @out = ([]);
foreach my $elt (@l){
    if( ref($elt) eq 'ARRAY' ){
        my $n = scalar(@$elt);
        my @_out;
        # expand 
        for( my $i=0; $i<$n; $i++ ){
            foreach my $o (@out){
                push(@_out, [@$o]);
            }
        }
        for( my $i=0; $i<@_out; $i++ ){
            push(@{$_out[$i]}, $elt->[$i % $n]);
        }
        @out = @_out;
    }
    else{
        foreach my $o (@out){
            push(@$o, $elt);
        }
    }
}

是否有更简洁的方法来完成此操作?

2 个答案:

答案 0 :(得分:2)

看起来您正在尝试计算阵列中元素的笛卡尔积。您可以使用CPAN中的Math::Cartesian::Product执行此操作:

use strict; 
use warnings; 

use Math::Cartesian::Product;
cartesian { print "@_","\n"; } 
   ([qw(foo)], [qw(A B)], [qw(bar)], [qw(X Y Z)], [qw(baz)]);

# outputs
# foo A bar X baz
# foo A bar Y baz
# foo A bar Z baz
# foo B bar X baz
# foo B bar Y baz
# foo B bar Z baz

注意,这确实需要您将每个输入元素放在arrayref中,如果您想要一个arrayrefs数组作为输出(从您的示例中),您将需要在块中编码该逻辑。

答案 1 :(得分:0)

虽然这是一个旧线程,但我想我会添加另一个可能的解决方案

模块Set::CrossProduct也会得到想要的结果。 (输入数组元素必须都是数组引用。)

SELECT * FROM Users WHERE login="john";
SELECT * FROM Users WHERE login="John";
SELECT * FROM Users WHERE login="JOHN";
SELECT * FROM Users WHERE login="jOHn";

数据转储输出

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dump;
use Set::CrossProduct;

my @l = (
  'foo',
  ['A', 'B'],
  'bar',
  ['X', 'Y', 'Z'],
  'baz',
);

# all elements of array must be array refs
@l = map ref eq 'ARRAY' ? $_ : [$_], @l;

my @wanted = Set::CrossProduct->new(\@l)->combinations;

dd \@wanted;