Выбор каждого n-го элемента из массива

Какой самый эффективный способ выбрать каждый n-й элемент из большого массива? Есть ли «умный» способ сделать это или зацикливать единственный способ?

Некоторые моменты, которые следует учитывать:

  • Массив довольно большой с 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++; } 

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

РЕДАКТИРОВАТЬ

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

Solutions Collecting From Web of "Выбор каждого n-го элемента из массива"

Цикл 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. Это может очень хорошо выполнить ужасно.

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

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

Я рекомендую использовать 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]; } 

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

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

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

Выполнение этого было бы проще, если бы вы могли начать работу с удаленным элементом и двигаться вперед, но опять же это будет работать только для массивов с числовой индексацией – и если бы это было так, вам не пришлось бы двигаться вперед вообще, вы просто сделали бы немного математики, чтобы пересмотреть его.

  • Числовые индексы – лучшее долгосрочное решение, но сложнее реализовать
  • Отслеживание – проще реализовать, но вам придется снова загрязняться при удалении элементов
  • Кэширование элементов – вы должны, вероятно, сделать это и для других двух решений, но самостоятельно, это будет быстро, пока массив не будет изменен, и в этом случае вам, вероятно, придется переделать его.

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

EDIT: создайте и сохраните отдельный массив с 205-ю элементами (которые обновляются вставляются или что-то в этом роде).

  • Создайте два массивных массива [205] [N]
  • Загрузка данных в массив
  • Доступ к 205-му элементу для каждого N

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

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

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

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

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

 $keys = array_keys($array); for ($i=0, $n=min(count($keys), 130000); $i<$n; $i += 205) { $result[] = $array[$keys[$i]]; }