2009-08-02 27 views
11

że mam $input tablicę, która zawiera coś takiego:Utrzymanie parzystych elementów tablicy?

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) 

Chcę uzyskać $output tablicę, która zawiera to:

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) 

Tablica $output zawiera połowę wartości, które były w $input; te, które miały nawet numerowane klucze na wejściu; pierwszy z nich utrzymuje, drugi nie, trzecia to i tak jeden ...

(Uwaga: klucze nie są zachowane, tylko wartości są ważne)

Jak mogłem Zrób to ? Przechowywanie tylko jednej z dwóch wartości tablicy?


Próbowałem już kilka pomysłów, a już kilka różnych rozwiązań:

Pierwszy pomysł: iteracyjne nad tablicy wejściowej i skopiować interesujące wartości do tablicy wyjściowej:

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

Drugi pomysł: iteracyjne nad tablicy i unset czego nie chcesz zachować:

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

Trzecia idea: użyć combinaison z 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)); 

Czwarty pomysł: o to samo, ale z 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)); 

Każdy inny pomysł? Nawet/szczególnie jeśli brzmi to trochę hacky czy coś?

Moim celem nie jest uzyskanie najbardziej wydajnej ani prostej składni; to tylko dla zabawy i ponieważ jestem ciekawa, właściwie^^

Jeśli tytuł nie używa właściwych słów do opisania tego, czego chcę, nie wahaj się powiedzieć; lub edytować to:-)

+0

edytowany tytuł i opis algorytmu trochę na żądanie. Osobiście użyłbym pierwszego pomysłu - jest to proste i dość jasne, co robisz. –

+0

Dzięki za zmiany :-) Cóż, właściwie "jak mogę to zrobić bez pętli przeze mnie" to pytanie pojawiające się kilka dni temu w pracy; kolega i pomyślałem o tym ... i ostatecznie użyliśmy rozwiązania "for" (pierwszego, które dałem): mniej zabawy, ale łatwiej zrozumieć, kiedy ktoś będzie musiał zachować nasz kod - i to jest jedna z najbardziej ważna rzecz w naszej pracy; ale nadal było to ciekawe pytanie i pomyślałem, że mogę tu dostać zabawne/interesujące propozycje ^^ –

+0

+1 za dobrze sformułowane pytanie z własnymi pomysłami – PatrikAkerstrand

Odpowiedz

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

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

var_dump($x); 

lub inny

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

lub z PHP 5.3 zamknięcia (co nie jest lepsze niż globalny w tym przypadku ;-))

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

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

var_dump($x); 
+0

Też fajne! dzięki :-) nie myślałem o używaniu zamknięcia (mój umysł nie jest jeszcze przyzwyczajony do tych w PHP, chyba ^^ (i nie mogę używać PHP 5.3 tak bardzo, jak bym chciał :-()) –

+1

+1 za używanie zamknięć i "iterator_to_array" (o których nie wiedziałem) –

2

Zakładając klawiszy numerycznych:

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

EDIT

Tu idzie mój nieco bardziej szalony rozwiązanie, które utrzymuje indeks ciągły bez ponownego indeksowania .; 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): Muszę przyznać, że to nie jest tak przerażająco różni się od twojego rozwiązania 'for', ale myślę, że już pokryłeś prawie wszystkie bazy. Większość rozsądnych rozwiązań powinna różnić się tylko syntaktycznym cukrem. :) – deceze

+0

To też zamierzałem zasugerować. Jeśli klawisze nie są numeryczne, możesz uruchomić tablicę za pomocą funkcji i utworzyć nową tablicę elementów za pomocą klawiszy numerycznych. Każdy element będzie wówczas tablicą pary klucz/wartość z oryginalnej tablicy. Zaletą operatora Modulus jest to, że można go wykorzystać do znalezienia wielu różnych elementów. Aby znaleźć co 5 element , jeśli ($ key% 5 == 0) Oznacza to podzielenie przez 5 i zwrócenie pozostałej wartości. Lista od 0 do 15 elementów zwróci 0, 5, 10 i 15, z których każdy zwróci resztę 0, gdy podzielona przez 5, np. 10/5 = 2 R0. –

+0

@deceze: tak, masz rację, nie ma "cudu" I konserwowalnego rozwiązania ^^ Ale to była zabawa ;-) Dzięki, tak, nie pomyślałeś o module! –

0

Niekoniecznie najbardziej efektywny sposób, ale skoro wspomniałeś, że nie było konieczności wymóg ...

Flip filtra, a następnie odwrócić z powrotem.

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

Może to spowodować nieoczekiwane/nieintuicyjne wyniki w zależności od danych wejściowych. Na przykład. $ 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; 
    } 

To najmniejsza wersja mogłem myśleć off.

+0

Czy czegoś nie brakuje? – deceze

+1

twoje oświadczenie, jeśli nie będziesz pracować. –

-1

utworzyć funkcję wrapper

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

Najmniejszy i najbardziej wydajny chyba.

+2

Z pewnością jest mały, ale co to jest? – deceze

+3

Fuj, globale! : P –

2

Jeśli używasz PHP 5.3 lub nowszy, lub jeśli masz zainstalowane rozszerzenie SPL (domyślnie będzie to PHP 5), możesz używać klas FilterIterator i 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); 

(Rekwizyty do VolkerK dla wskazując iterator_to_array())

Które prawidłowo Wyjścia to:

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

Nie wiem dlaczego, ale myślę, że to uwielbiam! Prawdopodobnie nie użyłbym go w aplikacji, którą ktoś inny będzie musiał utrzymać, ale zdecydowanie mi się podoba (i nie myślałem o SPL) .Dziękuję :-) (po prostu "(" to musi zostać usunięte w metodzie akceptacji, a następnie działa) –

+0

Zgadzam się, SPL jest prawdopodobnie przesadą w tym przypadku, ale takie rzeczy jak RecursiveIteratorIterator są nieocenione –

+0

To po prostu szkoda, że ​​ludzie (w tym ja, faktycznie) na ogół nie używają SPL wystarczająco :-( –

Powiązane problemy