Сохранение четных элементов массива?

Скажем, у меня есть массив $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;
  }

Это самая маленькая версия, которую я мог бы придумать.