Зачем такие сложности? Всё делается намного проще - без рекурсий и проверок множества дополнительных условий:
$input = 'Шла Саша по шоссе и сосала сушку';
$inp_arr = preg_split('#[[:space:]]+#s', trim($input)); // Список обрабатываемых слов
$current = array(); // Список уже обработанных слов
$result = array(implode(' ', $inp_arr)); // Добавляем в результат исходную фразу
while (count($inp_arr) > 1) { // Пока в списке обрабатываемых не менее 2 слов
$head = array(); // Голова списка обрабатываемых слов
$tail = $inp_arr; // Хвост списка обрабатываемых слов
while (count($tail) > 1) { // Пока в хвосте не менее 2 слов
$head[] = array_shift($tail); // Перенос первого слова хвоста в конец головы
// Добавляем комбинацию в результат
$result[] = array_merge($current, array(implode(' ', $head), implode(' ', $tail)));
}
$current[] = array_shift($inp_arr); // Перенос первого слова обрабатываемых в уже обработанные
}
var_export($result);
Вариант, который перебирает все комбинации, всё же удобнее сделать рекурсивным, но алгоритмически он проще, т.к. не надо заботиться о том, чтобы в $current было по одному слову:
$input="Шла Саша по шоссе и сосала сушку";
$result=generate(preg_split('#[[:space:]]+#s', trim($input)));
var_export($result);
function generate($inp){
$out=array(implode(' ', $inp));
$head=array();
while(count($inp)>1){
$head[]=array_shift($inp);
foreach(generate($inp) as $val){
$out[]=array_merge(array(implode(' ', $head)), (array)$val);
}
}
return $out;
}
Если нужно сортировать по длинам строк, то достаточно изменить порядок обработки: предыдущий вариант начинает перебор с пустой головы и длинного хвоста, а надо с длиной головы и пустого хвоста:
function generate($inp){
$out=array(implode(' ', $inp));
$tail=array();
while(count($inp)>1){
array_unshift($tail, array_pop($inp));
foreach(generate($tail) as $val){
$out[]=array_merge(array(implode(' ', $inp)), (array)$val);
}
}
return $out;
}
Если же нужно отсортировать результат по длинам строк независимо от того, в какой позиции эта строка находится, то проще всего - как и сказал
@Fesor - использовать отдельную сортировку результата. Например, вот так:
usort($result, function($val_1, $val_2){
// Получение кол-ва слов в строках сравниваемых вариантов
$len_1=array_map(function($data){ return count(preg_split('#[[:space:]]+#s', $data)); }, (array)$val_1);
$len_2=array_map(function($data){ return count(preg_split('#[[:space:]]+#s', $data)); }, (array)$val_2);
// Массивы кол-ва слов, отсортированные по убыванию
$sort_len_1=$len_1;
$sort_len_2=$len_2;
rsort($sort_len_1);
rsort($sort_len_2);
// Проверяем, что два варианта имеют разное кол-во слов в строках
for($i=0; $i<count($sort_len_1); $i++){
if($sort_len_1[$i]!=$sort_len_2[$i]){
return $sort_len_2[$i]-$sort_len_1[$i];
}
}
// К данному моменту варианты по длинам строк уже отсортированы
// Этот цикл сортирует варианты с одинаковыми длинами по местоположению длинных строк
// Если такая сортировка не требуется - удалить цикл
for($i=0; $i<count($len_1); $i++){
if($len_1[$i]!=$len_2[$i]){
return $len_2[$i]-$len_1[$i];
}
}
return 0;
});