Выбор каждого 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++;
}
Эти методы могут быть довольно медленными, есть ли способ улучшить? Или я просто раскалываю волосы здесь?
ИЗМЕНИТЬ
Хорошие ответы вокруг с правильными объяснениями, старались выбрать наиболее подходящий, как принятый ответ. Спасибо!
Ответы
Ответ 1
Цикл 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. Это может очень хорошо выполнить ужасно.
Ответ 2
Попробуйте ArrayIterator:: seek()
Кроме того, используя одну новую конструкцию Spl datastructures, может дать лучшие результаты, чем использование простых массивов.
Ответ 3
Я рекомендую использовать 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];
}
Ответ 4
Я думаю, что решение этой проблемы не связано ни с одним синтаксисом PHP, а с дизайном вашего кода.
Вы можете либо сделать числовое индексирование массива (возможно, не правдоподобным для вашего приложения), отслеживать каждый 205-й элемент или только один раз искать массив (кешировать список каждого 205-го элемента).
По моему мнению, отслеживание каждого 205-го элемента было бы проще реализовать. Вы просто сохраните счет всех элементов в базе данных или что-то еще, и каждый раз, когда элемент добавляется, проверьте по модулю счет. Если у вас есть еще 205-й элемент, добавьте его в массив. Ибо, когда элементы удаляются, это было бы сложнее. Возможно, вам придется перепроверить весь массив, чтобы перестроить все ваши 205-е элементы.
Выполнение этого было бы проще, если бы вы могли начать работу с удаленным элементом и двигаться вперед, но опять же это будет работать только для массивов с числовой индексацией - и если бы это было так, вам не пришлось бы двигаться вперед вообще, вы просто сделают небольшую математику, чтобы переосмыслить ее.
- Числовые индексы - лучшее долгосрочное решение, но сложнее реализовать
- Отслеживание - проще реализовать, но вам придется снова загрязняться при удалении элементов.
- Элементы кэширования - вы, вероятно, должны сделать это и для других двух решений, но самостоятельно, это будет быстро, пока массив не будет изменен, и в этом случае вам, вероятно, придется повторить его.
Ответ 5
Если это действительно узкое место, вы можете подумать над переосмыслением своего дизайна, чтобы сделать его численным индексом.
РЕДАКТИРОВАТЬ: или создать и поддерживать отдельный массив только с 205-ю элементами (который обновляется при вставке или что-то в этом роде).
Ответ 6
Вы не можете перемещать указатель массива, кажется, более одного раза за раз. Я лично использовал бы это:
reset($source);
$next = true;
while($next === true){
$result[] = current($source);
for(i=0;i<205;i++){
$next = next($source);
}
}
Если кто-то может найти функцию, которая может перемещать указатель массива более чем на один шаг за раз, у вас будет лучший ответ. Я думаю, это хорошо, хотя.
Ответ 7
- Создайте два массивных массива [205] [N]
- Загрузка данных в массив
- Доступ к 205-му элементу для каждого N
Может показаться глупым, но по определению это быстрее, поскольку вы напрямую обращаетесь к ячейкам памяти и не выполняете никаких сравнений.
Ответ 8
Вы можете использовать array_keys
для работы только с ключами массива.
$keys = array_keys($array);
for ($i=0, $n=min(count($keys), 130000); $i<$n; $i += 205) {
$result[] = $array[$keys[$i]];
}