【问题标题】:Why does Math::Cartesian::Product return blessed objects?为什么 Math::Cartesian::Product 返回祝福对象?
【发布时间】:2011-05-24 15:26:43
【问题描述】:

我注意到Math::Cartesian::Product 返回一个祝福对象数组,而不是一个简单的数组数组。我不知道为什么。我实际上需要做一些额外的工作(unbless)才能使用结果......

【问题讨论】:

    标签: perl cartesian-product bless


    【解决方案1】:

    我最近在List::Gen 中添加了一个cartesian 函数:

    • 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 的 coderef 返回的任何值。所以如果你想要数组引用,就这么简单:cartesian {\@_} ...


    另外,您还需要做哪些额外的工作来处理受祝福的参考?除了 ref 将返回的内容之外,祝福数组在任何意义上仍然是一个数组。如果您正在编写基于引用类型的开关逻辑,则应该使用Scalar::Utilreftype

    【讨论】:

      【解决方案2】:

      另一种选择是模块Set::CrossProduct,它会产生普通的、无祝福的数组引用:

      use Set::CrossProduct;
      my $iter = Set::CrossProduct->new([ \@foo, \@bar ]);
      
      while (my $tuple = $iter->get){
          ...
      }
      

      或者一次获取所有元组:

      my @tuples = $iter->combinations;
      

      【讨论】:

        【解决方案3】:

        它祝福cartesian返回的数组,以便在运行以下代码时

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

        ...它可以检测到$b 是先前调用该模块的结果。

        进行笛卡尔积运算很简单,如果该模块返回的数据不符合您的需求,请考虑自己从头开始编写运算。

        不管怎样,检查模块源代码发现它并不太好。

        【讨论】:

        • Set::CrossProduct 是一个不错的选择。见search.cpan.org/perldoc/Set::CrossProduct
        • 为了平衡思南的好选择,换一个坏的选择:my @cartesian = do { local $" = ','; };如果您的数组包含 glob 元字符,则会快速下降,但这不是 fun 吗?
        猜你喜欢
        • 2017-09-25
        • 2014-01-19
        • 2013-07-07
        • 2011-10-29
        • 2011-11-14
        • 2010-09-28
        • 2011-01-20
        • 1970-01-01
        • 2011-03-28
        相关资源
        最近更新 更多