2009-08-02 15 views
11

Dire che ho una matrice $input, che contiene qualcosa di simile:Mantenere gli elementi pari di un array?

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) 

voglio ottenere un array $output, che conterrebbe questo:

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) 

L'array $output contiene la metà dei valori che erano in $input; quelli che avevano persino numerato le chiavi nell'input; il primo è tenuto, secondo non è, terzo è, e così uno ...

(Nota: non vengono mantenute le chiavi, solo i valori sono importanti)

Come potrei Fai quello ? Mantenere solo uno su due valori dell'array?


Ho già provato alcune idee, e già un paio diverse soluzioni:

Prima idea: iterate sopra la matrice di ingresso, e copiare i valori interessanti per l'array di uscita:

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

seconda idea: iterate sopra la matrice, e unset quello che non voglio tenere:

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

terza idea: utilizzare un combinaison di 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)); 

quarta idea: circa la stessa cosa, ma 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)); 

Qualche altra idea? Anche/particolarmente se suona un po 'hacky o altro?

Il mio obiettivo non è quello di ottenere la sintassi più efficiente né semplice; è solo per divertimento e perché sono curioso, in realtà ^^

Se il titolo non usa le parole giuste per descrivere ciò che voglio, non esitare a dirlo; o modificarla:-)

+0

ho modificato il titolo e la descrizione dell'algoritmo un po 'come richiesto. Personalmente userò la prima idea: è semplice e abbastanza chiaro quello che stai facendo. –

+0

Grazie per le modifiche :-) Beh, in realtà, "come posso farlo senza loop da solo" è una domanda che è comparsa al lavoro un paio di giorni fa; un collega e ci ho pensato ... e alla fine abbiamo usato la soluzione "for" (la prima che ho dato): meno divertente, ma più facile da capire quando qualcuno dovrà mantenere il nostro codice - e questo è uno dei più cosa importante nel nostro lavoro; ma, era ancora una domanda interessante, e ho pensato di ottenere alcune proposte divertenti/interessanti qui ^^ –

+0

+1 per domande ben formulate con le proprie idee – PatrikAkerstrand

risposta

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

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

var_dump($x); 

o un altro

<?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 PHP 5.3 chiusura (che non è migliore di globale in questo caso ;-))

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

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

var_dump($x); 
+0

Anche quelli carini! grazie :-) non pensavo di usare una chiusura (la mia mente non è ancora abituata a quelli in PHP, credo ^^ (e non posso usare PHP 5.3 quanto vorrei :-()) –

+1

+1 per usare chiusure e per 'iterator_to_array' (che non sapevo di) –

2

tasti numerici Assumendo:

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

EDIT

Qui va mia soluzione leggermente più folle che mantiene l'indice continuo senza ri-indicizzazione .; 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): Devo ammettere che non è così terrificante diverso dalla tua soluzione 'for', ma penso che tu abbia già coperto quasi tutte le basi. La maggior parte delle soluzioni sensate dovrebbero differire sostanzialmente solo nello zucchero sintattico. :) – deceze

+0

Questo è quello che stavo per suggerire. Se le chiavi non sono numeriche, è possibile eseguire l'array attraverso una funzione e creare una nuova matrice di elementi con i tasti numerici. Ogni elemento sarebbe quindi un array della coppia chiave/valore dall'array originale. La cosa bella dell'operatore Modulus è che può essere usato per trovare ogni sorta di numero di elementi. Per trovare ogni 5 elemento if ($ chiave% 5 == 0) Ciò significa dividere per 5 e restituire il resto. Un elenco da 0 a 15 elementi restituirebbe 0, 5, 10 e 15 ciascuno dei quali restituisce un resto di 0 quando diviso per 5. e.g 10/5 = 2 R0. –

+0

@deceze: sì, hai ragione, non c'è "miracolo" e soluzione manutenibile ^^ Ma quello è stato il divertimento è ;-) Grazie comunque, non pensavo al modulo! –

0

Non necessariamente il metodo più efficace, ma dal momento che lei ha detto che non era necessariamente un requisito ...

a fogli mobili, filtro, poi capovolgere indietro.

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

Ciò potrebbe produrre risultati imprevisti/non intuitivi a seconda dell'input. Per esempio. $ input = array ('a', 'a', 'b'); -> $ output == array ('b') – VolkerK

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

Ecco la versione più piccola che potevo pensare off.

+0

Non ti manca qualcosa? – deceze

+1

la tua istruzione if non funzionerà. –

-1

creare una funzione wrapper

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

La più piccola e più efficiente immagino.

+2

Di certo è piccolo, ma che succede? – deceze

+3

yuck, globals! : P –

2

Se stai usando PHP 5.3 o versioni successive, oppure avere l'estensione SPL installata (per impostazione predefinita su PHP 5), è possibile utilizzare le classi FilterIterator e 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); 

(Props a VolkerK per sottolineare iterator_to_array())

quali uscite in modo corretto questo:

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

Non so perché, ma penso di amare questo! Probabilmente non lo userò in un'applicazione che qualcun altro dovrà mantenere, ma mi piace sicuramente (e non ho pensato a SPL). Grazie :-) (solo un '(' che deve essere rimosso nel metodo accept, e poi funziona) –

+0

Sono d'accordo, SPL è probabilmente eccessivo per questo caso, ma cose come RecursiveIteratorIterator ha un valore inestimabile –

+0

È semplicemente un peccato che le persone (incluso me stesso, in realtà) generalmente non utilizzino abbastanza SPL :-( –

Problemi correlati