2013-06-05 123 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數組的指針(已知長度)。缺點是字符串和數組的操作不同,優點是內存使用率較低。

由於字符只是非常短的字符串,所以要加入它們,我們使用與.的標準字符串連接。