Я посмотрел самый первый фрагмент кода на странице, на которую вы ссылались:
sub c{my$n=-1+shift;$n?map{my$c=$_;map$c.$_,c($n,@_)}@_:@_}
Я немного разложил его, чтобы сделать его более читабельным;также я внес в него некоторые изменения, чтобы сделать его более понятным (см. combinations
):
#!/usr/bin/perl
use strict;
use warnings;
sub c {
my $n=-1+shift;
$n ? map{
my $c = $_;
map $c . $_ , c($n ,@_)
} @_
: @_;
}
sub combinations {
my $number = shift; # remove the first item from @_
my @chars = @_; # the remainder of @_
$number --; # decrement $number, so that you will eventually exit
# from this recursive subroutine (once $number == 0)
if ($number) { # true as long as $number != 0 and $number not undef
my @result;
foreach my $char (@chars) {
my @intermediate_list = map { $char . $_ } combinations($number, @chars);
push @result, @intermediate_list;
}
return @result; # the current concatenation result will be used for creation of
# @intermediate_list in the 'subroutine instance' that called 'combinations'
}
else {
return @chars;
}
}
print join " ", combinations(2, "A", "B");
print "\n";
print join " ", c(2, "A", "B");
print "\n\n";
print join " ", combinations(3, "A", "B");
print "\n";
print join " ", c(3, "A", "B");
print "\n";
Обе версии работают одинаково и выдают одинаковый вывод:
AA AB BA BB
AA AB BA BB
AAA AAB ABA ABB BAA BAB BBA BBB
AAA AAB ABA ABB BAA BAB BBA BBB
Я включил некоторые комментарии в код, но, возможно, более длинное объяснение в порядке !?Итак, вот пример, чтобы проиллюстрировать, как все работает: допустим, у нас есть два элемента, «A» и «B», и мы хотим получить все возможные комбинации из 2 из этих элементов.В этом случае $number
первоначально будет равно 2 (как мы хотим получить пары), а @chars
будет равно ('A', 'B')
.
Первый раз combinations
называется, $number
уменьшается до 1, таким образом, условие if
выполняется, и мы входим в цикл foreach
.Это сначала устанавливает $char
в 'A'.Затем он вызывает combinations(1, ('A', 'B'))
.Поскольку $number
всегда уменьшается при вызове подпрограммы, $number
равно 0 в этой «дочерней подпрограмме», следовательно, потомок просто возвращает («A», «B»).Таким образом:
@intermediate_list = map { $char . $_ } ('A', 'B'); # $char eq 'A'
map
затем принимает оба «A» и «B» и объединяет каждый из них с «A» ($ char), таким образом, @intermediate_list
- это («AA», «AB»),В следующем раунде цикла foreach
то же самое делается с $char = B
, который устанавливает @intermediate_list
в ('BA', 'BB').
В каждом раунде содержимое @intermediate_list
вставляются в список результатов, следовательно, @result
в конечном итоге содержит все возможные комбинации.
Если вы хотите получить тройки вместо пар, вы, очевидно, начнете с $number = 3
, и будет вызван combinations
три раза.При втором вызове он вернет @result
, то есть список, содержащий пару.Каждый элемент из этого списка будет объединен с каждым символом начального набора символов.
Хорошо, я надеюсь, что это имеет смысл.Пожалуйста, спросите, если что-то не стало ясным.
РЕДАКТИРОВАТЬ : Пожалуйста, смотрите комментарий ysth ниже.