我正在尝试在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()
而不是List返回。
任何建议或其他更多优雅的笛卡尔产品解决方案将不胜感激。
答案 0 :(得分:7)
你的问题在于这一部分:
push @out_array, [$r . $c];
$r . $c
将两个标量连接成一个字符串。 [EXPR]
创建一个数组引用。你不想要一个引用,只需要简单的字符串:
push @out_array, $r . $c;
如果你不喜欢push,而不喜欢语法糖,你可以使用一个实现了collect / take的模块:
my @cross = gather {
for my $x (@A) {
for my $y (@B) {
take $x . $y;
}
}
};
这是实现的,例如List::Gather
或Syntax::Keyword::Gather
。
我自己喜欢精心设计的map
表达式:
my @cross = map { my $x = $_; map $x.$_, @B } @A;
(与for
相同,push
用于所有实际目的。)
注意:Perl没有与数组相关的“字符”概念。当需要单个字符时,这些字符由长度为1的字符串建模.Perl数组总是包含标量,但是对于(内存)性能原因,字符串不是作为Perl数组实现的,而是作为指向C数组(已知长度)的指针。缺点是字符串和数组的操作集不同,优点是内存使用量较少。
由于字符只是非常短的字符串,要加入它们,我们使用标准字符串连接.
。