Я должен был решить эту проблему несколько лет назад. Я не смог придумать свое собственное решение, но вместо этого наткнулся на этот замечательный кусок кода, который включает в себя умное и разумное использование map
вместе с рекурсией:
#!/usr/bin/perl
print "permute:\n";
print "[", join(", ", @$_), "]\n" for permute([1,2,3], [4,5,6], [7,8,9]);
sub permute {
my $last = pop @_;
unless(@_) {
return map([$_], @$last);
}
return map {
my $left = $_;
map([@$left, $_], @$last)
}
permute(@_);
}
Да, это выглядит безумно, но позвольте мне объяснить! Функция будет повторяться до тех пор, пока @_
не станет пустым, после чего она вернет ([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 с просьбой объяснить мне это.
Вы можете легко адаптировать это решение к вашей проблеме.