J'ai un tableau de tableaux:
Array (
[0] => Array (
[id] = 7867867,
[title] = 'Some Title'),
[1] => Array (
[id] = 3452342,
[title] = 'Some Title'),
[2] => Array (
[id] = 1231233,
[title] = 'Some Title'),
[3] => Array (
[id] = 5867867,
[title] = 'Some Title')
)
La nécessité d'aller dans un ordre spécifique:
Comment pourrais-je m'y prendre? J'ai déjà trié des tableaux et lu beaucoup d'autres articles à ce sujet, mais ils sont toujours basés sur des comparaisons (c'est-à-dire valueA <valeurB).
L'aide est appréciée.
Vous pouvez utiliser usort()
pour dicter avec précision la manière dont le tableau doit être trié. Dans ce cas, le tableau $order
peut être utilisé dans la fonction de comparaison.
L'exemple ci-dessous utilise un closure
pour vous simplifier la vie.
$order = array(3452342, 5867867, 7867867, 1231233);
$array = array(
array('id' => 7867867, 'title' => 'Some Title'),
array('id' => 3452342, 'title' => 'Some Title'),
array('id' => 1231233, 'title' => 'Some Title'),
array('id' => 5867867, 'title' => 'Some Title'),
);
usort($array, function ($a, $b) use ($order) {
$pos_a = array_search($a['id'], $order);
$pos_b = array_search($b['id'], $order);
return $pos_a - $pos_b;
});
var_dump($array);
La clé de ce fonctionnement est d'avoir les valeurs qui sont comparées, soit les positions des id
s dans le tableau $order
.
La fonction de comparaison fonctionne en recherchant les positions des identifiants de deux éléments à comparer dans le tableau $order
. Si $a['id']
vient avant $b['id']
dans le tableau $order
, la valeur de retour de la fonction sera alors négative ($a
est moins "flottant" vers le haut). Si $a['id']
vient après $b['id']
, la fonction retourne un nombre positif ($a
est supérieur, donc "puits").
Enfin, il n’existe aucune raison particulière d’utiliser une fermeture; c’est juste ma façon d’écrire ces sortes de fonctions à jeter rapidement. Il pourrait également utiliser une fonction nommée normale.
Prolonger réponse de salathe pour cette exigence supplémentaire:
Maintenant que se passe-t-il lorsque j'ajoute des éléments au tableau et non au tri? JE ne vous souciez pas de l'ordre dans lequel ils apparaissent, tant que cela vient après ceux-ci que j'ai précisé.
Vous devez ajouter deux conditions supplémentaires à la fonction de tri:
Le code révisé serait donc:
$order = array(
3452342,
5867867,
7867867,
1231233
);
$array = array(
array("id" => 7867867, "title" => "Must Be #3"),
array("id" => 3452342, "title" => "Must Be #1"),
array("id" => 1231233, "title" => "Must Be #4"),
array("id" => 5867867, "title" => "Must Be #2"),
array("id" => 1111111, "title" => "Dont Care #1"),
array("id" => 2222222, "title" => "Dont Care #2"),
array("id" => 3333333, "title" => "Dont Care #3"),
array("id" => 4444444, "title" => "Dont Care #4")
);
function custom_compare($a, $b){
global $order;
$a = array_search($a["id"], $order);
$b = array_search($b["id"], $order);
if($a === false && $b === false) { // both items are dont cares
return 0; // a == b
}
else if ($a === false) { // $a is a dont care item
return 1; // $a > $b
}
else if ($b === false) { // $b is a dont care item
return -1; // $a < $b
}
else {
return $a - $b;
}
}
shuffle($array); // for testing
var_dump($array); // before
usort($array, "custom_compare");
var_dump($array); // after
Sortie:
Before | After
-------------------------------+-------------------------------
array(8) { | array(8) {
[0]=> | [0]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(4444444) | int(3452342)
["title"]=> | ["title"]=>
string(12) "Dont Care #4" | string(10) "Must Be #1"
} | }
[1]=> | [1]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(3333333) | int(5867867)
["title"]=> | ["title"]=>
string(12) "Dont Care #3" | string(10) "Must Be #2"
} | }
[2]=> | [2]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(1231233) | int(7867867)
["title"]=> | ["title"]=>
string(10) "Must Be #4" | string(10) "Must Be #3"
} | }
[3]=> | [3]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(1111111) | int(1231233)
["title"]=> | ["title"]=>
string(12) "Dont Care #1" | string(10) "Must Be #4"
} | }
[4]=> | [4]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(5867867) | int(2222222)
["title"]=> | ["title"]=>
string(10) "Must Be #2" | string(12) "Dont Care #2"
} | }
[5]=> | [5]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(2222222) | int(1111111)
["title"]=> | ["title"]=>
string(12) "Dont Care #2" | string(12) "Dont Care #1"
} | }
[6]=> | [6]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(3452342) | int(3333333)
["title"]=> | ["title"]=>
string(10) "Must Be #1" | string(12) "Dont Care #3"
} | }
[7]=> | [7]=>
array(2) { | array(2) {
["id"]=> | ["id"]=>
int(7867867) | int(4444444)
["title"]=> | ["title"]=>
string(10) "Must Be #3" | string(12) "Dont Care #4"
} | }
} | }
Les autres réponses qui utilisent des méthodes avec des appels itérés de array_search()
ne sont pas aussi efficaces qu'elles peuvent l'être. En restructurant/retournant le tableau de recherche "order", vous pouvez complètement omettre tous les appels array_search()
- ce qui rend votre tâche beaucoup plus efficace et brève. Je vais utiliser "l'opérateur de vaisseau spatial" le plus moderne (<=>
), mais les techniques antérieures fonctionneront de la même manière pour la ligne de comparaison.
Méthode n ° 1 - usort
lorsque toutes les valeurs id
existent dans $order
( Demo )
$order=array_flip([3452342,5867867,7867867,1231233]); // restructure with values as keys, and keys as order (ASC)
// generating $order=[3452342=>0,5867867=>1,7867867=>2,1231233=>3];
$array=[
['id'=>7867867,'title'=>'Some Title'],
['id'=>3452342,'title'=>'Some Title'],
['id'=>1231233,'title'=>'Some Title'],
['id'=>5867867,'title'=>'Some Title']
];
usort($array,function($a,$b)use($order){
return $order[$a['id']]<=>$order[$b['id']];
// when comparing ids 3452342 & 1231233, the actual comparison is 0 vs 3
});
// uasort() if you want to preserve keys
var_export($array);
Méthode n ° 2 - usort
lorsque certaines valeurs id
n'existent pas dans $order
( Demo )
* remarque, isset()
est un appel moins coûteux que array_search()
$order=array_flip([3452342,5867867,7867867,1231233]); // restructure with values as keys, and keys as order (ASC)
// generating $order=[3452342=>0,5867867=>1,7867867=>2,1231233=>3];
$outlier=1+max($order);
// generating $outlier=4
$array=[
['id'=>7867867,'title'=>'Some Title'],
['id'=>3452342,'title'=>'Some Title'],
['id'=>'foo','title'=>'Some Title'],
['id'=>1231233,'title'=>'Some Title'],
['id'=>'bar','title'=>'Some Title'],
['id'=>5867867,'title'=>'Some Title']
];
usort($array,function($a,$b)use(&$order,$outlier){ // make $order modifiable with &
if(!isset($order[$a['id']])){$order[$a['id']]=$outlier;} // update lookup array with [id]=>[outlier number]
if(!isset($order[$b['id']])){$order[$b['id']]=$outlier;} // and again
return $order[$a['id']]<=>$order[$b['id']];
});
var_export($array);
Méthode alternative n ° 2 - usort
lorsque certaines valeurs id
n'existent pas dans $order
... J'aimerais également mentionner que dans certains cas, éviter le double appel itéré de isset()
peut être moins attrayant que de préparer complètement le tableau $order
avant d'appeler usort()
.
Cette ligne unique garantira qu'il ne manque aucune valeur id
, éliminant ainsi le besoin de rien d'autre que la ligne de comparaison à l'intérieur de la fonction de tri. ( Full Snippet Demo )
$order=array_replace(array_fill_keys(array_column($array,'id'),$outlier),$order);
@salathe Pour ceux d'entre vous qui ont du mal à comprendre ce que fait l'usager de Salathe:
Chaque élément de $ array est un "champion" dans un tournoi qui doit être au début d'un nouveau tableau (sauf qu'au lieu d'être numéro un, ils veulent être numéro 0).
$ a est le champion local et $ b le champion adverse dans un match.
$ pos_a et $ pos_b du rappel sont les attributs qui seront utilisés dans la lutte pour les champions a et b. Dans ce cas, cet attribut est l'indice de l'id des champions dans l'ordre $.
Ensuite, il y a la bagarre au retour. Nous regardons maintenant pour voir s'il est préférable d'avoir plus ou moins d'attribut. Lors d'une bataille d'usurpation, le champion local veut un nombre négatif pour pouvoir être plus tôt dans le tableau. Le champion à l'extérieur veut un nombre positif. Et devrait-il y avoir un 0 c'est une cravate.
Donc, en suivant cette analogie lorsque l'attribut champions à l'extérieur (index par ordre) est soustrait de l'attribut équipes à domicile, plus l'attribut champions à l'extérieur est grand, moins il est probable qu'il obtiendra un nombre positif. Cependant, si vous inversiez la manière dont les attributs sont utilisés, l'attribut du champion local est maintenant soustrait de celui du champion absent. Dans ce cas, un nombre plus élevé pour le champion en déplacement est plus susceptible de lui faire terminer le match par un nombre positif.
Le code ressemblerait à ceci:
remarque: le code est exécuté plusieurs fois, comme dans un vrai tournoi qui compte beaucoup de batailles pour décider qui sera le premier (c.-à-d. 0/début du tableau).
//tournament with goal to be first in array
usort($champions, function ($home, $away) use ($order) {
$home_attribute = array_search($a['id'], $order);
$away_attribute = array_search($b['id'], $order);
//fight with desired outcome for home being negative and away desiring positive
return $home_attribute - $away_attribute;
});
Sans sorte, vous pouvez aussi l'obtenir.
S'il n'y a pas d'identifiant en double;
<?php
$order = array(3452342, 5867867, 7867867, 1231233);
$array = array(
array('id' => 7867867, 'title' => 'Some Title'),
array('id' => 3452342, 'title' => 'Some Title'),
array('id' => 1231233, 'title' => 'Some Title'),
array('id' => 5867867, 'title' => 'Some Title'),
);
$order = array_flip($order);
$array = array_column($array,null,"id");
$result = array_replace($order,$array);
var_dump(array_values($result));
Avec un identifiant en double,
<?php
$order = array(3452342, 5867867, 7867867, 1231233);
$array = array(
array('id' => 7867867, 'title' => 'Some Title'),
array('id' => 3452342, 'title' => 'Some Title'),
array('id' => 1231233, 'title' => 'Some Title'),
array('id' => 5867867, 'title' => 'Some Title'),
);
$order_dict = array_flip($order);
$order_dict = array_combine($order,array_fill(0,count($order),[]));
foreach($array as $item){
$order_dict[$item["id"]][] = $item;
}
//$order_dict = array_filter($order_dict); // if there is empty item on some id in $order array
$result = [];
foreach($order_dict as $items){
foreach($items as $item){
$result[] = $item;
}
}
var_dump($result);