Взрыв строки, возвращение массива, удаляющего одну строку для каждого ключа - PullRequest
0 голосов
/ 28 октября 2018

Допустим, у нас есть строка Быстрая коричневая лиса перепрыгивает через ленивую собаку

Я хочу вернуть массив со следующим (удаляя одно слово каждый раз).

array:9 [▼
  0 => "The quick brown fox jumps over the lazy dog"
  1 => "quick brown fox jumps over the lazy dog"
  2 => "brown fox jumps over the lazy dog"
  3 => "fox jumps over the lazy dog"
  4 => "jumps over the lazy dog"
  5 => "over the lazy dog"
  6 => "the lazy dog"
  7 => "lazy dog"
  8 => "dog"
]

Я быстро запустил следующую функцию, которая делает это.

function wordsToArr($str)
    {

           $words =[];
           $ex_str =explode(' ',$str);


           foreach($ex_str as $k=>$v){

              $words[] =implode(' ',$ex_str);

              unset($ex_str[$k]);
            }

           return $words;
    }

Теперь мой вопрос: есть ли более быстрый способ, целесообразно ли это сделать?

ОБНОВЛЕНИЕ По запросу я выполнил тест.Также пробовал это со следующей функцией:

function wordsToArr2($str)
    {

        $words =[$str];
        while($pos =strpos ( $str , ' ')){

            $str=substr($str,($pos+1));
            $words[] =$str;
        }

        return $words;

    }

Использовал этот скрипт для сравнения: https://gist.github.com/blongden/2352583

Результаты:

Explode (wordsToArr) string run: 317,505/sec
strpos/substr (wordsToArr2) run: 542,725/sec

Мой вопрос остается, есть лиЛюбая другая функция, чтобы сделать это еще быстрее?

1 Ответ

0 голосов
/ 28 октября 2018

Похоже, что strpos и substr могут быть наиболее последовательными.

Альтернатива, однако, поскольку у вас уже есть список слов, вместо удаления каждого слова вы можете использовать вместо него конкатенацию,Сокращение количества вызовов функций за итерацию.

Пример: https://3v4l.org/j5YMm

$str = 'The quick brown fox jumps over the lazy dog';
$base = array_reverse(explode(' ', $str));
$words = [$placeholder = array_shift($base)];
foreach($base as $word) {
    $words[] = $placeholder = $word . ' ' . $placeholder;
}
$words = array_reverse($words);
print_r($words);

Результаты

числа очень противоречивы в 3v4l - тест для васверсия сервера и PHP

PHP 5.6.38

implode 100 times in: 0.00047302/sec
strpos 100 times in:  0.00035501/sec
concat 100 times in:  0.00034595/sec

Возвращает

Array
(
    [0] => The quick brown fox jumps over the lazy dog
    [1] => quick brown fox jumps over the lazy dog
    [2] => brown fox jumps over the lazy dog
    [3] => fox jumps over the lazy dog
    [4] => jumps over the lazy dog
    [5] => over the lazy dog
    [6] => the lazy dog
    [7] => lazy dog
    [8] => dog
)

Примечание Существует также много способов реализации конкатенации.

Вы можете заменить array_shift, который требует переиндексации массива, на array_pop, что немного снижает сложность кода операции.

$base = explode(' ', $str);
$words = [$placeholder = array_pop($base)];
$base = array_reverse($base);

Вы также можете использовать условие для клавиши в пределах foreach, чтобы определить, следует ли использовать конкатенацию, с небольшой потерей производительности.

$base = array_reverse(explode(' ', $str));
$s = '';
foreach ($base as $i => $w) {
    $words[] = $s = ($i === 0 ? $w : $w . ' ' . $s);
}

Обновлено

В качестве еще одной альтернативы для уменьшения количества вызовов кода операции вы можете использовать for count(), используя $i-- для обработки массива в обратном порядке.С возможностью замены $l = count($base) - 1; на end($base); $l = key($base); или использованием array_key_last для PHP 7.3

Пример https://3v4l.org/VfJku

$base = explode(' ', $str);
$l = count($base)-1;
$words = [$placeholder = $base[$l--]];
for ($i=$l; $i>=0;$i--) {
    $words[] = $placeholder =   $base[$i] . ' ' . $placeholder;
}
$words = array_reverse($words);
print_r($words);

PHP 5.6.38

strpos 100 times in: 0.00043607/sec
concat 100 times in: 0.00044894/sec
end/key 100 times in: 0.00037289/sec
count-- 100 times in: 0.00036097/sec
...