2009-08-02 10 views
11

Decir que tengo una serie $input, que contiene algo como esto:¿Mantener elementos pares de una matriz?

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) 

Quiero conseguir una matriz $output, que contendría la siguiente:

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) 

La matriz $output contiene la mitad de los valores que estaban en $input; los que tenían claves numeradas en la entrada; el primero se mantiene, segundo no es, tercero es, y por lo que uno ...

(Nota: las claves no se conservan, sólo los valores son importantes)

Cómo podría Haz eso ? ¿Manteniendo solo uno en dos valores de la matriz?


que ya han intentado algunas ideas, y ya tienen un par de diferentes soluciones:

primera idea: iterar sobre la matriz de entrada, y copiar los valores interesantes para la matriz de salida:

$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)); 

segunda idea: iterar sobre la matriz, y unset lo que no quiero seguir:

$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)); 

tercera idea: utilizar un Combinaison de 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)); 

Cuarta idea: de lo mismo, pero con 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)); 

¿Alguna otra idea? Incluso/particularmente si suena un poco hacky o algo?

Mi objetivo no es obtener la sintaxis más eficiente ni simple; es solo por diversión y porque tengo curiosidad, en realidad ^^

Si el título no está utilizando las palabras adecuadas para describir lo que quiero, no dude en decirlo; o editarlo:-)

+0

que editaron el título y la descripción del algoritmo un poco de lo solicitado. Personalmente, usaría la primera idea: es simple y bastante claro lo que estás haciendo. –

+0

Gracias por las ediciones :-) Bueno, en realidad, "¿cómo puedo hacer eso sin bucles?" Es una pregunta que surgió en el trabajo hace un par de días; un colega y lo pensé ... y finalmente usamos la solución "para" (la primera que di): menos divertido, pero más fácil de entender cuando alguien tendrá que mantener nuestro código, y ese es uno de los más algo importante en nuestro trabajo; pero, todavía era una pregunta interesante, y pensé que podría obtener algunas proposiciones divertidas/interesantes aquí ^^ –

+0

+1 para preguntas bien formuladas con ideas propias – PatrikAkerstrand

Respuesta

15
<?php 
$x = range('a', 'f'); 

$x = array_map('array_shift', 
     array_chunk($x, 2) 
    ); 

var_dump($x); 

u otro

<?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); 

o con un cierre PHP 5.3 (que no es mejor que global en este caso ;-))

<?php 
$x = range('a', 'f'); 

$x = array_filter($x, function($e) use(&$c) { return 0===$c++%2; }); 

var_dump($x); 
+0

¡Bonitos también! gracias :-) no pensé en usar un cierre (mi mente aún no está acostumbrada a aquellos en PHP, supongo ^^ (y no puedo usar PHP 5.3 tanto como me gustaría :-()) –

+1

+1 para usar cierres y para el 'iterator_to_array' (que no sabía). –

2

teclas numéricas Suponiendo:

foreach ($array as $key => $value) { 
    if ($key % 2 != 0) { 
     unset($array[$key]); 
    } 
} 

EDITAR

Aquí va mi solución ligeramente más loco que mantiene el índice continua sin necesidad de volver a clasificar .; O)

foreach ($array as $key => $value) { 
    if (!($key%2)) { 
     $array[$key/2] = $value; 
    } 
} 
$array = array_slice($array, 0, ceil(count($array)/2)); 
+0

@Pascal (OP): Tengo que admitir que esto no es tan terrorífico diferente de su solución 'para', pero creo que cubrió casi todas las bases usted mismo. La mayoría de las soluciones sensatas deberían diferir en azúcar sintáctico. :) – deceze

+0

Esto es lo que iba a sugerir también. Si las teclas no son numéricas, quizás pueda ejecutar la matriz a través de una función y crear una nueva matriz de elementos con las teclas numéricas. Cada elemento sería una matriz del par clave/valor de la matriz original. Lo bueno del operador Modulus es que puede usarse para encontrar todo tipo de elementos. Para encontrar cada 5to elemento if ($ key% 5 == 0) Esto significa dividir por 5 y devolver el resto. Una lista de 0 a 15 elementos devolvería 0, 5, 10 y 15, cada uno de los cuales arrojaría un resto de 0 cuando se dividiera por 5. p. Ej. 10/5 = 2 R0. –

+0

@deceze: sí, tienes razón, no hay ningún "milagro" Y solución de mantenimiento ^^ Pero eso fue lo divertido; ;) Gracias de todos modos, ¡no pensé en el módulo! –

0

No necesariamente el método más eficiente, pero ya que ha mencionado que no era necesariamente un requisito ...

lado, filtro, luego voltear hacia atrás.

<?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); 
?> 
+1

Esto podría producir resultados inesperados/no intuitivos dependiendo de la entrada. P.ej. $ input = array ('a', 'a', 'b'); -> $ salida == array ('b') – VolkerK

-2
function dropHalf($a){ 
    $f=0; 
    foreach($a as $k=>$v) 
     if($f = ! $f) 
     unset($a[$k]); 
    return $a; 
    } 

Esa es la versión más pequeña de lo que podía pensar.

+0

¿No te estás perdiendo algo? – deceze

+1

su declaración if no funcionará amigo. –

-1

crear una función de contenedor

function getInput($i) 
{ 
    global $input; 
    return $input[$i*2]; 
} 

El más pequeño y más eficiente supongo.

+2

Ciertamente es pequeño, pero ¿qué es eso? – deceze

+3

yuck, globals! : P –

2

Si está utilizando PHP 5.3 o posterior, o tiene la extensión SPL instalada (lo hará de forma predeterminada en PHP 5), puede usar las clases FilterIterator y 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); 

(Apoyos a VolkerK para señalar iterator_to_array())

que da salida a esta correctamente:

Array 
(
    [0] => a 
    [1] => c 
    [2] => e 
    [3] => g 
    [4] => i 
) 
+0

No sé por qué, pero creo que me encanta este! Probablemente no lo use en una aplicación que alguien más tendrá que mantener, pero definitivamente me gusta (y no pensé en SPL). Gracias :-) (solo un '(' que tiene que ser eliminado en el método de aceptación, y luego funciona) –

+0

Estoy de acuerdo, SPL es probablemente exagerado para este caso, pero cosas como RecursiveIteratorIterator es inestimable. –

+0

Es una lástima que las personas (incluyéndome a mí, en realidad) generalmente no usen el SPL lo suficiente :-( –

Cuestiones relacionadas