Autor Zpráva
nethor
Profil
Zdravím,
mám asociativní pole
$Arr = array(
    'znacka'     => 'object1',
    'typ'         => 'object2',
    'model'     => 'object3',
);

a potřebuji podle indexu získat předchozí a následující index.

Nedaří se mi najít funkci, která nastaví pointer na pozici podle indexu.
Pak by se daly použít fce prev() a next().

Problém jde obejít pomocí foreach(), ale asi by to mělo jít jednodušeji.

Poradíte?
Keeehi
Profil
php.net/manual/en/arrayiterator.seek.php
nethor
Profil
Keeehi:
To asi nepůjde použít u asociativního pole, když má být parametr integer.
Dan Charousek
Profil
Vlastní funkcí bych to řešil asi takto, ale je dost dobře možné, že existuje i jednodušší řešení:

function getNextAndPreviousKey(&$previous, $key, &$next, $array, $step = 1) {
    
    $keys    = array_keys($array);
    $pos    = array_search($key, $keys);
            
    $previous    = isset($keys[$pos - $step]) ? $keys[$pos - $step] : null;
    $next        = isset($keys[$pos + $step]) ? $keys[$pos + $step] : null;
    
}

$Arr = array(
    'znacka'    => 'object1',
    'typ'        => 'object2',
    'model'        => 'object3',
);

$key = "typ";

getNextAndPreviousKey($previous, $key, $next, $Arr);

echo "
    Previous key: $previous, value: $Arr[$previous]<br>
    Current key: $key, value: $Arr[$key]<br>
    Next key: $next, value: $Arr[$next]
";
Alphard
Profil
nethor [#1]:
Lze si vytvořit funkci find(), která požadovaný prvek najde iteraci a pak používat prev() a next() dle potřeby.

Dle vzoru prev a next s referencí.
function find(&$arr, $key) {
  reset($arr);
  while (($k = key($arr)) !== null && $k !== $key) next($arr);
}

find($array, 'hledanyKlic');
echo next($array);
echo next($array);
Popřípadě funkce findByKey() a findByValue(), princip je asi jasný.

Já bych se na tu referenci asi vykašlal a předával klasicky hodnotou, mně se to líbí víc.
function find($arr, $key) {
  reset($arr);
  while (($k = key($arr)) !== null && $k !== $key) next($arr);
  return $arr;
}

Případně si to obalit do vlastní třídy.
$storage->find('mujKlic')->getNext();


Dan Charousek [#4]:
Jestli vám to vyhovuje, tak fajn, ale podle mě jsou s funkcemi s tolika parametry a ještě referencovanými jenom problémy. Když už bych měl mít podobně komplexní funkci, udělal bych samostatně prev a next verzi (která může být jen obálkou pro volání té současné).

Edit: Doplnil jsem do těch funkcí ještě reset().
Dan Charousek
Profil
Alphard:
Možná jsem to s tím „Vlastní funkcí bych to řešil asi takto“ asi hodně nadsadil. Osobně bych preferoval nějakou pěknou obalovací třídu, ale bylo to první co mě napadlo a počítal jsem s tím, že se nebude jednat o ultimátní řešení. Ale zas na druhou stranu si myslím, že každý nápad hozený do ringu se počítá. Přeci jen může motivovat ostatní k ještě lepším řešením :).

<?php
class ArrWrapper {
    
    private $arr;
    
    public function __construct(Array $arr) {
        $this->arr = $arr;
    }
    
    public function findByKey($key) {
        // edit: Vzhledem k tomu, že je kód inspirován Alphardovo funkcí, také zde chyběl reset ^^
        reset($this->arr);
        while(($k = key($this->arr)) !== null && $k !== $key) next($this->arr);
        return new ArrWrapper($this->arr);
    }
    
    public function getNext() {return next($this->arr);}
    public function getPrev() {return prev($this->arr);}
    
}

$arr = new ArrWrapper(array(
    "auto"        => "Modré",
    "kolo"        => "Zelené",
    "letadlo"    => "Bílé"
));

echo $arr->findByKey("auto")->getNext(); // Zelené
echo $arr->findByKey("kolo")->getNext(); // Bílé
echo $arr->findByKey("kolo")->getPrev(); // Modré
Edit: Doplnil jsem výstupy.
nethor
Profil
Díky,
WorkAround třída je docela překvápko, čekal jsem, že tyhle fce budou přímo někde v PHP...
Alphard
Profil
nethor:
WorkAround třída je docela překvápko
Ona je to teda spíš funkce zabalená do třídy. Moje původní představa byla obálka nad datovým objektem, která bude mj. interně pracovat s ukazatelem na prvek pole bez neustálého kopírování samotného pole a samozřejmě zapouzdřit do té třídy i metody prev/next, ne je volat mimo. Tohle jsem si špatně pamatoval, omlouvám se.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0