Сохранение четных элементов массива?
Скажем, у меня есть массив $input
, который содержит что-то вроде этого:
array
0 => string 'a' (length=1)
1 => string 'b' (length=1)
2 => string 'c' (length=1)
3 => string 'd' (length=1)
4 => string 'e' (length=1)
5 => string 'f' (length=1)
6 => string 'g' (length=1)
7 => string 'h' (length=1)
8 => string 'i' (length=1)
9 => string 'j' (length=1)
Я хочу получить массив $output
, который будет содержать это:
array
0 => string 'a' (length=1)
1 => string 'c' (length=1)
2 => string 'e' (length=1)
3 => string 'g' (length=1)
4 => string 'i' (length=1)
Массив $output
содержит половину значений, которые были в $input
; те, которые даже пронумеровали ключи на входе; первая сохраняется, вторая - нет, третья - одна и т.д....
(Примечание: ключи не сохраняются, важны только значения)
Как я могу это сделать? Сохранение только одного из двух значений массива?
Я уже пробовал некоторые идеи и уже имею пару различных решений:
Первая идея: итерация по входному массиву и копирование интересных значений в выходной массив:
$input = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', );
$output = array();
$nbr = count($input);
for ($i = 0 ; $i < $nbr ; $i += 2) {
$output[] = $input[$i];
}
var_dump(array_values($output));
Вторая идея: итерация по массиву и unset
то, что я не хочу сохранять:
$input = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', );
$output = $input;
$nbr = count($input);
for ($i = 1 ; $i < $nbr ; $i += 2) {
unset($output[$i]);
}
var_dump(array_values($output));
Третья идея: используйте комбинацию array_flip
, range
, array_diff_key
,...:
$input = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', );
$output = array();
$keys_to_exclude = array_flip(range(1, count($input)-1, 2));
$output = array_diff_key($input, $keys_to_exclude);
var_dump(array_values($output));
Четвертая идея: о том же, но с array_intersect_key
:
$input = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', );
$output = array();
$keys_to_include = array_flip(range(0, count($input)-1, 2));
$output = array_intersect_key($input, $keys_to_include);
var_dump(array_values($output));
Любая другая идея? Даже/особенно, если это звучит немного хаки или что-то еще?
Моя цель - не получить самый эффективный и простой синтаксис; это просто для удовольствия и потому, что мне любопытно, на самом деле ^^
Если название не использует правильные слова для описания того, что я хочу, не стесняйтесь рассказывать; или отредактируйте его : -)
Ответы
Ответ 1
<?php
$x = range('a', 'f');
$x = array_map('array_shift',
array_chunk($x, 2)
);
var_dump($x);
или другой
<?php
class ArrayEvenIterator extends ArrayIterator {
public function next() {
parent::next();
return parent::next();
}
}
$x = range('a', 'f');
$x = iterator_to_array(new ArrayEvenIterator( $x ), false);
var_dump($x);
или с закрытием php 5.3 (что не лучше глобального в этом случае;-))
<?php
$x = range('a', 'f');
$x = array_filter( $x, function($e) use(&$c) { return 0===$c++%2; });
var_dump($x);
Ответ 2
Предполагая числовые клавиши:
foreach ($array as $key => $value) {
if ($key % 2 != 0) {
unset($array[$key]);
}
}
ИЗМЕНИТЬ
Вот мое немного более безумное решение, которое поддерживает индекс без переиндексации.; О)
foreach ($array as $key => $value) {
if (!($key%2)) {
$array[$key/2] = $value;
}
}
$array = array_slice($array, 0, ceil(count($array)/2));
Ответ 3
Если вы используете PHP 5.3 или новее или имеете расширение SPL (по умолчанию на PHP 5), вы можете использовать FilterIterator и ArrayObject.
class EvenKeysFilter extends FilterIterator
{
private function iseven($keyval)
{
return (($keyval % 2) == 0);
}
public function accept()
{
$keyval = $this->getInnerIterator()->key();
return ($this->iseven($keyval));
}
}
$input = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', );
$inputobj = new ArrayObject($input);
$evenFilterIter = new EvenKeysFilter($inputobj->getIterator());
$output = iterator_to_array($evenFilterIter, false);
print_r($output);
(Подставляет VolkerK для указания iterator_to_array()
)
Что правильно выводит это:
Array
(
[0] => a
[1] => c
[2] => e
[3] => g
[4] => i
)
Ответ 4
Не обязательно самый эффективный метод, но поскольку вы упомянули, что это не обязательно требование...
щелкнуть, отфильтровать, затем откинуть назад.
<?php
function even($var)
{
return(!($var & 1));
}
$input = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', );
$flipped = array_flip($input);
$filtered = array_filter($flipped, 'even');
$output = array_flip($filtered);
?>
Ответ 5
создать функцию обертки
function getInput($i)
{
global $input;
return $input[$i*2];
}
Самый маленький и самый эффективный, я думаю.
Ответ 6
function dropHalf($a){
$f=0;
foreach($a as $k=>$v)
if($f = ! $f)
unset($a[$k]);
return $a;
}
Это самая маленькая версия, которую я мог бы придумать.