两个字符串的笛卡尔积

3
我正在尝试在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
$r . $c 组成的字符串推入 @out_array 数组中作为一个数组引用。如果你不需要这个引用,可以跳过方括号。函数 split 永远返回字符串,而非引用。 - amon
@amon 谢谢,我对那个点有些困惑。 - Hunter McMillen
1个回答

7

您的问题出在这个部分:

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

$r . $c将这两个标量连接成一个字符串。[EXPR]创建一个数组引用。你不需要引用,只需要普通的字符串:

push @out_array, $r . $c;

如果您不喜欢使用push,但想要一些语法糖的话,您可以使用实现gather/take的模块:
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数组的指针(已知长度)。缺点是字符串和数组有不同的操作集,优点是更少的内存使用。

由于字符只是非常短的字符串,因此我们使用标准字符串连接符.来连接它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接