2010-12-13 2 views
1

Я заметил, что Math::Cartesian::Product возвращает массив благословленных объектов вместо простого массива массивов. Я не мог понять, почему. Я на самом деле нужно сделать некоторые дополнительные работы (лишишь) использовать результаты ...Почему Math :: Cartesian :: Продукт возвращает блаженные объекты?

ответ

2

Альтернатива является модулем Set::CrossProduct, который даст обычные, неблагословленные ссылки на массивы:

use Set::CrossProduct; 
my $iter = Set::CrossProduct->new([ \@foo, \@bar ]); 

while (my $tuple = $iter->get){ 
    ... 
} 

Или получить все кортежи сразу:

my @tuples = $iter->combinations; 
1

Он благословляет массивы, возвращаемые cartesian так, что, когда некоторый код, как в следующем запуске

$b = $cartesian $a1, $a2; 
$c = $cartesian $b, $a3; 

... это может обнаружить, что $b является результатом предыдущего вызова модуля.

Выполнение декартовой операции с продуктом является чем-то тривиальным, если данные, возвращенные этим модулем, не соответствуют вашим потребностям, подумайте о том, чтобы выполнить операцию самостоятельно с нуля.

В любом случае, проверка исходного кода модуля показывает, что он не слишком велик.

+2

'Set :: CrossProduct' является хорошей альтернативой.См. Http://search.cpan.org/perldoc/Set::CrossProduct –

+1

В качестве противовеса хорошей альтернативе Синана вместо этого есть плохая альтернатива: my @cartesian = do {local $ "= ','; <{@ foo } {@ bar}>}; Это быстро ломается, если ваши массивы содержат метасимволы glob, но разве это не * fun *? – Hugmeir

4

Я добавил cartesian функцию List::Gen в последнее время:

  • cartesian CODE LIST_of_ARRAYREF

    cartesian вычисляет декартово произведение любого количества рефлексов массива, каждый из которых может быть любого размера. возвращает генератор

    use List::Gen 'cartesian'; 
    my $product = cartesian {$_[0] . $_[1]} [qw/a b/], [1, 2]; 
    print "@$product"; # 'a1 a2 b1 b2' 
    

«генератор», возвращенное ленивый привязал массив, который будет генерировать значения, когда его спросили о них. Есть также и другие итерационные методы доступа:

my $pairs = cartesian {@_} [qw/$ @ %/], ['a'..'z'], [1 .. 3]; 

while (my @tuple = $pairs->next) { # $pairs->reset; #$pairs->index = 5; ... 
    print @tuple, ', '; 
} 
# $a1, $a2, $a3, $b1, $b2, $b3, $c1, $c2, $c3, $d1, $d2, $d3, $e1 ... 

Я не знаю, насколько велики наборов вы будете работать с есть, но преимущество использования вышеуказанного подхода является то, что требования к памяти для генератора остается O(1)

my $digits = cartesian {join '' => @_} ([0..9]) x 10; 

say for @$digits[10**9 - 3 .. 10**9 + 3]; 

# 0999999998 
# 0999999999 
# 1000000000 
# 1000000001 
# 1000000002 
# 1000000003 

, который вычисляет только 6 элементов набора и не сохраняет ничего.

Как видно из примеров, возвращаемое значение cartesian само по себе является объектом-генератором, но последующие возвращаемые значения этого объекта - это то, что передается кододером cartesian. Так что если вы хотите, ссылки на массивы, это так просто, как: cartesian {\@_} ...


Кроме того, что дополнительная работа вы должны сделать, чтобы иметь дело с блаженной ссылкой? Благословенный массив по-прежнему является массивом во всех смыслах, за исключением того, что вернет ref. Если вы пишете логику коммутатора на основе ссылочного типа, то Scalar::Utilreftype - это то, что вы должны использовать.