Выбор каждого энного объекта от массива

Каков был бы самый эффективный способ выбрать каждый энный объект из большого массива? Существует ли 'умный' способ сделать, это или действительно ли цикличное выполнение - единственный путь?

Некоторые вопросы для рассмотрения:

  • Массив является довольно большим с 130 000 объектов
  • Я должен выбрать каждый 205-й объект
  • Объекты численно не индексируются, таким образом, for($i = 0; $i <= 130000; $i += 205) не будет работать

До сих пор это - наиболее эффективный способ, который я придумал:

$result = array();
$i = 0;
foreach($source as $value) {

    if($i >= 205) {
        $i = 0;
    }

    if($i == 0) {
        $result[] = $value;
    }

    $i++;
}

Или то же с модулем:

$result = array();
$i = 0;
foreach($source as $value) {
    if($i % 205 == 0) {
        $result[] = $value;
    }
    $i++;
}

Эти методы могут быть довольно медленными, там какой-либо способ улучшиться? Или я просто крохоборствую здесь?

Править

Хорошие ответы все вокруг с надлежащими объяснениями, которые попробовали для выбора самого подходящего как принятого ответа. Спасибо!

14
задан Tatu Ulmanen 21 December 2009 в 11:52
поделиться

8 ответов

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

Этот ответ должен выполняться быстрее.

$result = array();
$i = 0;
foreach($source as $value) {
    if ($i++ % 205 == 0) {
        $result[] = $value;
    }
}

У меня нет времени на тестирование, но вы могли бы использовать вариант решения @haim, если сначала численно проиндексируете массив. Стоит попробовать посмотреть, сможете ли вы получить какой-либо выигрыш по сравнению с моим предыдущим решением:

$result = array();
$source = array_values($source);
$count = count($source);
for($i = 0; $i < $count; $i += 205) {
    $result[] = $source[$i];
}

Это во многом будет зависеть от того, насколько оптимизирована функция array_values. Он вполне мог работать ужасно.

15
ответ дан 1 December 2019 в 09:01
поделиться
  • Создать двумерный массив [205] [N]
  • Загрузить данные в массив
  • Доступ к 205-му элементу для каждого N

Может показаться глупым, но по определению это самый быстрый, поскольку вы получаете доступ к ячейкам памяти напрямую и не выполняете никаких сравнений.

0
ответ дан 1 December 2019 в 09:01
поделиться

Попробуйте ArrayIterator :: seek ()

Кроме того, использование одной из новых структур данных Spl может дать лучшие результаты, чем использование простых массивов.

7
ответ дан 1 December 2019 в 09:01
поделиться

Я рекомендую использовать array_slice

$count = count($array) ;
for($i=205;$i<$count;$i+=205){
    $result[] = array_slice($array,$i,1);
}

Если бы ваш массив был численно проиндексирован, это было бы очень быстро:

$count = count($array) ;
for($i=205;$i<$count;$i+=205){
    $result[] = $array[$i];
}
6
ответ дан 1 December 2019 в 09:01
поделиться

Если это действительно узкое место, вы можете подумать о переосмыслении вашего дизайна, чтобы сделать его числовым индексом .

РЕДАКТИРОВАТЬ: Или создайте и поддерживайте отдельный массив только с 205-ю элементами (который обновляется при вставке или что-то подобное).

1
ответ дан 1 December 2019 в 09:01
поделиться

Вы можете ' t перемещать указатель массива, кажется, более одного раза за раз. Я бы лично использовал это:

reset($source);
$next = true;
while($next === true){
    $result[] = current($source);
    for(i=0;i<205;i++){
        $next = next($source);
    }
}

Если кто-то сможет найти функцию, которая может перемещать указатель массива более чем на один шаг за раз, у вас будет лучший ответ. Я думаю, что это хорошо.

0
ответ дан 1 December 2019 в 09:01
поделиться

Вы можете использовать array_keys для работы только с ключами массива.

$keys = array_keys($array);
for ($i=0, $n=min(count($keys), 130000); $i<$n; $i += 205) {
    $result[] = $array[$keys[$i]];
}
-1
ответ дан 1 December 2019 в 09:01
поделиться

Я думаю, что решение этой проблемы лежит не в синтаксисе PHP, а в дизайне вашего кода.

Вы можете либо сделать массив числовым (может быть неправдоподобным для вашего приложения), либо отслеживать каждый 205-й элемент, либо искать в массиве только один раз (кэшировать список каждого 205-го элемента).

На мой взгляд, отслеживать каждый 205-й элемент было бы проще. Вы просто будете вести подсчет всех элементов в базе данных или что-то в этом роде, и каждый раз, когда элемент добавляется, проверять модуло подсчета. Если у вас есть еще один 205-й элемент, добавьте его в массив. Ведь когда элементы удаляются, это будет более хитро. Возможно, вам придется перепроверить весь массив, чтобы перестроить все 205-е элементы.

Это было бы проще, если бы вы могли начать с удаленного элемента и двигаться вперед, но опять же это работало бы только для численно проиндексированных массивов - и если бы это было так, вам вообще не пришлось бы двигаться вперед, вы бы просто сделали небольшие математические расчеты, чтобы перестроить его.

  • Числовые индексы - лучшее долгосрочное решение, но более сложное в реализации
  • Keeping track - проще в реализации, но вам снова придётся пачкаться, когда вы удаляете элементы
  • Кэширование элементов - вы, вероятно, должны сделать это и для двух других решений, но само по себе это будет быстро, пока массив не будет изменён, и в этом случае вам, вероятно, придётся переделывать его заново.
2
ответ дан 1 December 2019 в 09:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: