2013-06-05 59 views
2

我想在Perl中编写一个计算两个字符串的交叉乘积(笛卡尔乘积)的函数。我在Python中有类似的代码,看起来像这样:两个字符串的笛卡尔积

def cross(A, B): 
    "Cross product of elements in A and elements in B." 
    return [a+b for a in A for b in B] 

我怎样才能以优雅的方式模仿这个列表理解?

这是我到目前为止有:

# compute the cross product of two Strings 
# cross('12','AB') = ((1,A), (1,B), (2,A), (2,B)) 
sub cross { 
    # unpack strings 
    my ($A, $B) = @_; 

    # array to hold products 
    my @out_array; 

    # split strings into arrays 
    my @A_array = split(//, $A); 
    my @B_array = split(//, $B); 

    # glue the characters together and append to output array 
    for my $r (@A_array) { 
     for my $c (@B_array) { 
      push @out_array, [$r . $c]; 
     } 
    } 

    return \@out_array; 
} 

这不是工作正是我所期望的,由于某种原因,参考即将由split(),而不是一个列表返回。

任何建议或其他更多优雅的笛卡尔产品解决方案将不胜感激。

+4

'push @out_array,[$ r。 $ c];'将包含一个字符串的数组引用推送到'@ out_array'。你不需要参考,所以跳过方括号。 'split' * always *返回字符串,永远不会引用。 – amon

+0

@amon谢谢,我对这一点感到困惑。 –

回答

7

你的问题是,在这一部分:

push @out_array, [$r . $c]; 

$r . $c地连接了两个标量为字符串。 [EXPR]创建数组引用。你不想要的参考,只是简单的字符串:

push @out_array, $r . $c; 

如果你不喜欢推,但语法糖,你可以使用实现采集模块/带:

my @cross = gather { 
    for my $x (@A) { 
    for my $y (@B) { 
     take $x . $y; 
    } 
    } 
}; 

这实现了例如通过List::GatherSyntax::Keyword::Gather

我自己很喜欢精心map表达式:

my @cross = map { my $x = $_; map $x.$_, @B } @A; 

(同forpush所有的实际目的)。


注:Perl不具有的是关系到阵列“人物”的概念。当需要单个字符时,这些字符串由长度为1的字符串建模。Perl数组总是包含标量,但对于(内存)性能原因,字符串不是作为Perl数组实现的,而是作为指向C数组的指针(已知长度)。缺点是字符串和数组的操作不同,优点是内存使用率较低。

由于字符只是非常短的字符串,所以要加入它们,我们使用与.的标准字符串连接。