在Perl中,如何获得多个集合的笛卡尔积?
我想用 Perl 进行排列。例如,我有三个数组: ["big", "tiny", "small"]
然后我有 ["red", "yellow", "green"]
以及[“苹果”、“梨”、“香蕉”]
。
我如何得到:
["big", "red", "apple"] ["big", "red", "pear"] ..etc.. ["small", "green", "banana"]
我知道这叫做排列。但我不知道该怎么做。我也不知道我可以有多少个数组。可能有三四个,所以我不想做嵌套循环。
I want to do permutation in Perl. For example I have three arrays: ["big", "tiny", "small"]
and then I have ["red", "yellow", "green"]
and also ["apple", "pear", "banana"]
.
How do I get:
["big", "red", "apple"] ["big", "red", "pear"] ..etc.. ["small", "green", "banana"]
I understand this is called permutation. But I am not sure how to do it. Also I don't know how many arrays I can have. There may be three or four, so I don't want to do nested loop.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
这实际上不是排列,而是笛卡尔积。请参阅Math::Cartesian::Product。
输出:
That's actually not permutation but Cartesian product. See Math::Cartesian::Product.
Output:
现在以 twitter 形式:
sub prod { reduce { [ map { my $i = $_;地图 [ @$_, $i ], @$a } @$b ] } [[]], @_ }
Now in twitter-form:
sub prod { reduce { [ map { my $i = $_; map [ @$_, $i ], @$a } @$b ] } [[]], @_ }
几年前我就必须解决这个问题。我无法提出自己的解决方案,而是遇到了这段精彩的代码,其中涉及巧妙而明智地使用
map
以及递归:是的,这看起来很疯狂,但请允许我解释一下!该函数将递归直到
@_
为空,此时它返回([1], [2], [3])
(三个数组引用的列表)上一级递归。在该级别,$last
是对包含[4, 5, 6]
的数组的引用。然后,外部映射的主体运行三次,将
$_
设置为[1]
,然后是[2]
,最后是[3]
。然后,对于外部映射的每次迭代,内部映射都会在(4, 5, 6)
上运行,并返回([1, 4], [1, 5], [1, 6])
,([2, 4], [2, 5], [2, 6])
,最后([3, 4], [3, 5], [3, 6])
。最后一个递归调用返回
([1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3 , 4], [3, 5], [3, 6])
。然后,它针对
[7,8,9]
运行结果,得到[1, 4, 7], [1, 4, 8] , [1, 4, 9], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 6, 7], [1, 6, 8], [ 1, 6, 9], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 6, 7], [2, 6, 8], [2, 6, 9], [3, 4, 7], [3, 4, 8], [3, 4, 9]、[3、5、7]、[3、5、8]、[3、5、9]、[3、6、7]、[3、6、8]、[3、6、9]
我记得在 perlmonks.org 上发布了一个问题,要求有人向我解释这一点。
您可以轻松地根据您的问题调整此解决方案。
I had to solve this exact problem a few years ago. I wasn't able to come up with my own solution, but instead ran across this wonderful piece of code which involves clever and judicious use of
map
along with recursion:Yes, this looks crazy, but allow me to explain! The function will recurse until
@_
is empty, at which point it returns([1], [2], [3])
(a list of three arrayrefs) to the previous level of recursion. At that level$last
is a reference to an array that contains[4, 5, 6]
.The body of the outer map is then run three times with
$_
set to[1]
, then[2]
and finally[3]
. The inner map is then run over(4, 5, 6)
for each iteration of the outer map and this returns([1, 4], [1, 5], [1, 6])
,([2, 4], [2, 5], [2, 6])
, and finally([3, 4], [3, 5], [3, 6])
.The last but one recursive call then returns
([1, 4], [1, 5], [1, 6], [2, 4], [2, 5], [2, 6], [3, 4], [3, 5], [3, 6])
.Then, it runs that result against
[7,8,9]
, which gives you[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 6, 7], [1, 6, 8], [1, 6, 9], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 6, 7], [2, 6, 8], [2, 6, 9], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 6, 7], [3, 6, 8], [3, 6, 9]
I remember posting a question on perlmonks.org asking someone to explain this to me.
You can easily adapt this solution to your problem.
如果您愿意,可以使用我的 Set::CrossProduct 模块。您不必遍历整个空间,因为它为您提供了一个迭代器,因此您可以控制一切。
You can use my Set::CrossProduct module if you like. You don't have to traverse the entire space since it gives you an iterator, so you're in control.
如果
那么你可以简单地这样做:
对于两个数组
@ xs
和@ys
:对于三个数组
@xs
、@ys
、@zs
IF
then you can simply do this:
For two arrays
@xs
and@ys
:For three arrays
@xs
,@ys
,@zs
这是我的解决方案,不需要任何模块,并且可以根据需要使用任意多组。
例子:
Here is my solution that doesn't require any module and that can take as many sets as you want.
EXAMPLES :