Käytössä on PHP. Minulla on moniulotteinen taulukko.
Array (
[183] => Array (
[info] => Array (
[name] => Ben
[points] => 4800
)
)
[380] => Array (
[info] => Array (
[name] => Ruben
[points] => 14500
)
)
[450] => Array (
[info] => Array (
[name] => Alex
[points] => 4800
)
)
)PHP-koodi järjestää/lajittelee taulukon ja se toimii ihan oikein.
Ensimmäinen lajittelukriteeri on points, jonka mukaan lajitellaan laskevasti. Toinen kriteeri on name, lajittelu nousevasti.
uasort($array, function($a, $b) { if ($a['info']['points'] == $b['info']['points']) { return strcmp($a['info']['name'], $b['info']['name']); } return $b['info']['points'] - $a['info']['points']; });
Kun PHP-koodi lajittelee taulukon, syntyvä taulukko on tällainen:
Array (
[380] => Array (
[info] => Array (
[name] => Ruben
[points] => 14500
)
)
[450] => Array (
[info] => Array (
[name] => Alex
[points] => 4800
)
)
[183] => Array (
[info] => Array (
[name] => Ben
[points] => 4800
)
)
)Muuten homma toimii hienosti, mutta haluaisin saada lisättty myös position-arvot mieluummin lajittelun lomassa tai jos se ei onnistu, niin sitten vasta lajittelun jälkeen vaikkapa foreach-silmukassa.
Mitä enemmän pisteitä (points), sitä pienempi position. Jos points on sama, on myös position-arvojen oltavat samat.
Lopullinen taulukko pitäisi saada tällaiseksi:
Array (
[380] => Array (
[info] => Array (
[name] => Ruben
[points] => 14500
[position] => 1
)
)
[450] => Array (
[info] => Array (
[name] => Alex
[points] => 4800
[position] => 2 /* koska Alexilla points on pienempi kuin Rubenilla */
)
)
[183] => Array (
[info] => Array (
[name] => Ben
[points] => 4800
[position] => 2 /* koska Benillä points on sama kuin Alexilla */
)
)
)Mitä homma hoituisi mahdollisimman nopeasti foreach-silmukalla tai jollakin muulla tavalla?
$position = 0; $position_for_points = 0; $points = null; foreach ($taulukko as $i => $_) { $position += 1; if ($taulukko[$i]["info"]["points"] !== $points) { $position_for_points = $position; $points = $taulukko[$i]["info"]["points"]; } $taulukko[$i]["info"]["position"] = $position_for_points; }
Sivuhuomio: Joku ehkä ihmettelee, miksi en käytä koodissa viittauksia (&$rivi). Syy on se, että viittauksilla tulee helposti virheitä, koska silmukan jälkeen viittaus jää viimeiseen riviin ja samannimisen muuttujan käyttäminen myöhemmin ilman viittausta muuttaakin odottamatta sitä taulukon viimeistä riviä.
Kiitos. Miksi !== eikä != tuossa? Eikö muuttujan $points arvoa päivitetä välillä? En nyt pysty tätä testaamaan, serveri alhaalla...
xxmss kirjoitti:
Miksi !== eikä != tuossa?
Jotta koodi toimisi myös tilanteessa, jossa kärjellä on nolla pistettä. 0 == null mutta 0 !== null.
xxmss kirjoitti:
Eikö muuttujan $points arvoa päivitetä välillä?
Päivitetään. Poistin sen rivin vahingossa, kun muokkasin koodia. Nyt koodi on taas oikein edellisessä viestissä.
Kiitos lisäinfosta. Voisiko alussa olla $points = 0; ja sitten if-lauseessa != $points?
Oliomallinen ratkaisu iteraattoria käyttäen. Tällöin rankkaus tehdään lennosta taulukkoa loopatessa ja välttyy ylimääräiseltä silmukalta.
<?php
class RankIterator extends ArrayIterator {
/**
* Iterator index 0...n
*/
protected $i;
/**
* Ranking
*/
protected $pos;
/**
* Function used to compare two values.
*/
protected $comparison;
/**
* Key to use for storing item ranking.
*/
protected $rank_key;
/**
* Value from last iteration to be used for comparison.
*/
protected $last;
public function __construct(array $data, $rank_key, callable $comparison) {
parent::__construct($data);
$this->rank_key = $rank_key;
$this->comparison = $comparison;
}
public function current() {
$item = parent::current();
if ($this->i > 0) {
$delta = call_user_func($this->comparison, $this->last, $item);
if ($delta > 0) {
$this->pos = $this->i + 1;
} elseif ($delta < 0) {
throw new Error('Source data is not sorted');
}
}
$item[$this->rank_key] = $this->pos;
$this->last = $item;
return $item;
}
public function next() {
parent::next();
$this->i++;
}
public function rewind() {
parent::rewind();
$this->i = 0;
$this->pos = 1;
$this->last = null;
}
}
$data = [
['points' => 100, 'name' => 'Miska'],
['points' => 95, 'name' => 'Laura'],
['points' => 87, 'name' => 'Siiri'],
['points' => 87, 'name' => 'Jaakko'],
['points' => 45, 'name' => 'Petteri'],
];
$iterator = new RankIterator($data, 'rank', function($a, $b) {
return $a['points'] - $b['points'];
});
print_r(iterator_to_array($iterator));Aihe on jo aika vanha, joten et voi enää vastata siihen.