Почему Math :: Cartesian :: Product возвращает благословенные объекты? - PullRequest
1 голос
/ 13 декабря 2010

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

Ответы [ 3 ]

4 голосов
/ 14 декабря 2010

Я недавно добавил 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 само по себе является объектом-генератором, но последующие возвращаемые значения этого объекта - это то, что возвращает coderef, переданный cartesian. Так что если вам нужны ссылки на массивы, это просто: cartesian {\@_} ...


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

2 голосов
/ 13 декабря 2010

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

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

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

Или получите все кортежи одновременно:

my @tuples = $iter->combinations;
1 голос
/ 13 декабря 2010

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

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

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

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

...