Comment trier un tableau multidimensionnel par valeur?

1129

Comment puis-je trier ce tableau en fonction de la valeur de la clé "order"? Même si les valeurs sont actuellement séquentielles, elles ne le seront pas toujours.

Array
(
    [0] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )

    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )

    [2] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
)
stef
la source
le moyen le plus rapide consiste à utiliser le module de tableau de tri isomorphe qui fonctionne nativement dans le navigateur et le nœud, prenant en charge tout type d'entrée, les champs calculés et les ordres de tri personnalisés.
Lloyd

Réponses:

1734

Essayez un usort , si vous êtes encore sur PHP 5.2 ou antérieur, vous devrez d'abord définir une fonction de tri:

function sortByOrder($a, $b) {
    return $a['order'] - $b['order'];
}

usort($myArray, 'sortByOrder');

À partir de PHP 5.3, vous pouvez utiliser une fonction anonyme:

usort($myArray, function($a, $b) {
    return $a['order'] - $b['order'];
});

Et enfin avec PHP 7, vous pouvez utiliser l' opérateur de vaisseau spatial :

usort($myArray, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

Pour étendre cela au tri multidimensionnel, référencez les deuxième / troisième éléments de tri si le premier est nul - mieux expliqué ci-dessous. Vous pouvez également l'utiliser pour trier les sous-éléments.

usort($myArray, function($a, $b) {
    $retval = $a['order'] <=> $b['order'];
    if ($retval == 0) {
        $retval = $a['suborder'] <=> $b['suborder'];
        if ($retval == 0) {
            $retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
        }
    }
    return $retval;
});

Si vous devez conserver les associations de touches, utilisez uasort()- voir la comparaison des fonctions de tri des tableaux dans le manuel

Christian Studer
la source
2
Ma formulation est un peu décalée, je vais la modifier. Ce que je voulais dire, c'est que si vous n'êtes pas sur PHP 5.3, vous devez créer une fonction spéciale juste pour ce tri particulier (ce qui n'est pas très élégant). Sinon, vous pourriez utiliser une fonction anonyme sur place.
Christian Studer
23
@Jonathan: Vous ne pouvez pas vraiment voir la plupart du travail que fait PHP. Il prend le tableau et commence par deux éléments, qu'il a transmis à cette fonction définie par l'utilisateur. Votre fonction est alors chargée de les comparer: Si le premier élément est plus grand que le second, retournez un entier positif, s'il est plus petit, retournez-en un négatif. S'ils sont égaux, retournez 0. PHP envoie ensuite deux autres éléments à votre fonction et continue de le faire, jusqu'à ce que le tableau soit trié. La fonction ici est très courte, elle pourrait être beaucoup plus compliquée si vous ne comparez pas des entiers.
Christian Studer
61
Protip: utilisez uasort()si vous souhaitez conserver les clés du tableau.
thaddeusmt le
15
Soyez prudent si les valeurs triables sont des nombres décimaux. Si la fonction de tri obtient $ a = 1 et $ b = 0,1, la différence est de 0,9, mais la fonction renvoie un entier, dans ce cas 0, donc $ a et $ b sont considérés comme égaux et triés incorrectement. Il est plus fiable de comparer si $ a est supérieur à $ b ou égal et de renvoyer -1, 1 ou 0 en conséquence.
Greenlandi
37
Il m'a fallu un certain temps pour le découvrir. Pour trier l'ordre inverse (DESC), vous pouvez changer $ a et $ b. Donc $ b ['commande'] - $ a ['commande']
JanWillem
285
function aasort (&$array, $key) {
    $sorter=array();
    $ret=array();
    reset($array);
    foreach ($array as $ii => $va) {
        $sorter[$ii]=$va[$key];
    }
    asort($sorter);
    foreach ($sorter as $ii => $va) {
        $ret[$ii]=$array[$ii];
    }
    $array=$ret;
}

aasort($your_array,"order");
o0 '.
la source
7
@ noc2spam Je suis heureux de vous aider, mais pensez à suivre la suggestion de studer qui est probablement plus efficace et sûrement plus ordonnée!
o0 '.
1
@Lohoris mec sûr, je vérifie cela aussi. Hier aurait été une journée plus difficile au bureau si je n'avais pas trouvé cette question :-)
Gogol
hmm ne peux pas ajouter une réponse .. eh bien je le mets ici parce que je n'ai pas besoin de ces points stupides: donc pour un tri multidimensionnel c'est (presque) la même chose (srry vous devez copier coller et reformater): function aasort (& $ array , $ clé1, $ clé2, $ clé3) {$ sorter = array (); $ ret = array (); reset ($ array); foreach ($ array as $ ii => $ va) {$ sorter [$ ii] = getPrice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ sorter); foreach ($ sorter as $ ii => $ va) {$ ret [$ ii] = $ array [$ ii]; } $ array = $ ret; }
Jaxx0rr
3
Beaucoup plus facile à appliquer que la réponse ci-dessus
Marcel
1
TU ES INCROYABLE!! FONCTIONNE COMME CHARME POUR PHP 7.2 MERCI BEAUCOUP CHER :)
Kamlesh
270

J'utilise cette fonction:

function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
    $sort_col = array();
    foreach ($arr as $key=> $row) {
        $sort_col[$key] = $row[$col];
    }

    array_multisort($sort_col, $dir, $arr);
}


array_sort_by_column($array, 'order');
Tom Haigh
la source
3
Fonctionne très bien. La solution unique pouvant ajouter un sens de tri. Merci!
Ivo Pereira
2
Pour une alternative qui prend en charge les directions de tri et de nombreuses fonctionnalités supplémentaires, vous voudrez peut-être jeter un coup d'œil à ma réponse ici - elle a également l'avantage qu'elle n'utilise pas array_multisortet n'a donc pas besoin de préallouer $sort_col, économisant du temps et de la mémoire .
Jon
Fonctionne très bien pour moi, mais ... pourquoi est-il nécessaire de spécifier &$arrau lieu de juste $arr?
Radu Murzea
2
@RaduMurzea donc le tableau est passé par référence et peut être modifié par la fonction, plutôt que par la fonction qui reçoit une copie
Tom Haigh
1
@AdrianP. : le tableau est passé par référence, il modifiera donc le tableau passé plutôt que de renvoyer une copie triée
Tom Haigh
72

J'utilise habituellement usort et passe ma propre fonction de comparaison. Dans ce cas, c'est très simple:

function compareOrder($a, $b)
{
  return $a['order'] - $b['order'];
}
usort($array, 'compareOrder');

En PHP 7 en utilisant l'opérateur de vaisseau spatial:

usort($array, function($a, $b) {
    return $a['order'] <=> $b['order'];
});
Jan Fabry
la source
4
Bon sang, j'étais 30 secondes plus lent. N'est-ce pas $ a - $ b?
Christian Studer
3
Je me trompe toujours. Je pense au manuel: la valeur de retour doit être inférieure à zéro si le premier argument est considéré comme inférieur au second. Donc, si $a['order']est 3 et $b['order']est 6, je reviendrai -3. Correct?
Jan Fabry
3
Eh bien, vous retournez b - a, ce sera donc 3. Et donc trié incorrectement.
Christian Studer
26
Ah. D'ACCORD. J'utilisais l'arithmétique non logique, où l'idée dans votre tête ne correspond pas aux mots que vous produisez. Ceci est étudié le plus souvent le vendredi après-midi.
Jan Fabry
dans certains cas, la réponse ci-dessus est renvoyer un résultat incorrect. référence stackoverflow.com/questions/50636981/…
Bilal Ahmed
45

Une approche pour y parvenir serait la suivante

    $new = [
              [
                'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4',
                'title' => 'Flower',
                'order' => 3,
              ],

              [
                'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594',
                'title' => 'Free',
                'order' => 2,
              ],

              [
                'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
                'title' => 'Ready',
                'order' => 1,
              ],
    ];

    $keys = array_column($new, 'order');

    array_multisort($keys, SORT_ASC, $new);

    var_dump($new);

Résultat:

    Array
    (
        [0] => Array
            (
                [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
                [title] => Ready
                [order] => 1
            )

        [1] => Array
            (
                [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
                [title] => Free
                [order] => 2
            )

        [2] => Array
            (
                [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
                [title] => Flower
                [order] => 3
            )

    )
ajuchacko91
la source
18

Pour trier le tableau selon la valeur de la clé "title", utilisez:

uasort($myArray, function($a, $b) {
    return strcmp($a['title'], $b['title']);
});

strcmp compare les chaînes.

uasort () conserve les clés du tableau telles qu'elles ont été définies.

BK
la source
strcmp est une aide notable pour les types varchar, j'ai aimé cette réponse pour faire court et rapide
StudioX
17
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

Cela prend en charge les alphabets majuscules et minuscules.

Nitrodbz
la source
4
Comment cela répond-il à la question du tri par clé de tableau particulière?
Seano
12

Utiliser array_multisort(),array_map()

array_multisort(array_map(function($element) {
      return $element['order'];
  }, $array), SORT_ASC, $array);

print_r($array);

DEMO

Ghanshyam Nakiya
la source
Notez que cette approche émettra un avis. array_multisortréférence son premier paramètre.
Kami Yang
5

L'approche la plus flexible serait d'utiliser cette méthode

Arr::sortByKeys(array $array, $keys, bool $assoc = true): array

Voici pourquoi:

  • Vous pouvez trier par n'importe quelle clé (également imbriquée comme 'key1.key2.key3'ou ['k1', 'k2', 'k3'])

  • Fonctionne à la fois sur des tableaux associatifs et non associatifs ( $associndicateur)

  • Il n'utilise pas de référence - retourne un nouveau tableau trié

Dans votre cas, ce serait aussi simple que:

$sortedArray = Arr::sortByKeys($array, 'order');

Cette méthode fait partie de cette bibliothèque .

Minwork
la source
1

Avouons-le: php n'a PAS une simple fonction prête à l'emploi pour gérer correctement chaque scénario de tri de tableau.

Cette routine est intuitive, ce qui signifie un débogage et une maintenance plus rapides:

// automatic population of array
$tempArray = array();
$annotations = array();
// ... some code
// SQL $sql retrieves result array $result 
// $row[0] is the ID, but is populated out of order (comes from 
// multiple selects populating various dimensions for the same DATE 
// for example
while($row = mysql_fetch_array($result)) {
    $needle = $row[0];
    arrayIndexes($needle);  // create a parallel array with IDs only
    $annotations[$needle]['someDimension'] = $row[1]; // whatever
}
asort($tempArray);
foreach ($tempArray as $arrayKey) {
    $dataInOrder = $annotations[$arrayKey]['someDimension']; 
    // .... more code
}

function arrayIndexes ($needle) {
    global $tempArray;
    if (!in_array($needle,$tempArray)) {
        array_push($tempArray,$needle);
    }
}
Tony Gil
la source
4
"Avouons-le: php n'a PAS une simple fonction prête à l'emploi pour gérer correctement chaque scénario de tri de tableau." C'est exactement ce pour quoi usort / ksort / asort sont conçus pour ^^ '
Ben Cassinat
3
En fait, PHP a beaucoup de fonctions de tri qui peuvent être utilisées pour gérer chaque scénario de tri de tableau.
axiac
En ce qui concerne le débogage et la maintenance, l'utilisation de globalest un énorme drapeau rouge et est généralement déconseillée . Pourquoi est mysql_fetch_arraydémontré pour cette question au lieu du tableau source de l'OP, et qu'il n'y a aucune explication de ce que fait votre code et ce que l'on peut attendre du résultat? Dans l'ensemble, il s'agit d'une approche très complexe pour atteindre le résultat final souhaité.
fyrye
@tonygil Je ne suis pas en mesure de déterminer quels sont vos résultats attendus à partir de votre réponse et de l'ensemble de données de l'OP. Cela peut vous sembler évident, mais je ne sais pas comment votre réponse répond à la question du PO. Cependant, vous pouvez passer par référence au lieu d'utiliser globalsee: 3v4l.org/FEeFC Cela produit une variable explicitement définie, plutôt qu'une variable qui peut être modifiée et accessible globalement.
fyrye
0

Vous pouvez également trier un tableau multidimensionnel pour plusieurs valeurs comme

$arr = [
    [
        "name"=> "Sally",
        "nick_name"=> "sal",
        "availability"=> "0",
        "is_fav"=> "0"
    ],
    [
        "name"=> "David",
        "nick_name"=> "dav07",
        "availability"=> "0",
        "is_fav"=> "1"
    ],
    [
        "name"=> "Zen",
        "nick_name"=> "zen",
        "availability"=> "1",
        "is_fav"=> "0"
    ],
    [
        "name"=> "Jackson",
        "nick_name"=> "jack",
        "availability"=> "1",
        "is_fav"=> "1"
    ],
    [
        "name"=> "Rohit",
        "nick_name"=> "rod",
        "availability"=> "0",
        "is_fav"=> "0"
    ],

];

avec

usort($arr,function($a,$b){
    $c = $b['is_fav'] - $a['is_fav'];
    $c .= $b['availability'] - $a['availability'];
    $c .= strcmp($a['nick_name'],$b['nick_name']);
    return $c;
});

Sortie utilisant print_r($arr):

Array
(
    [0] => Array
        (
            [name] => Jackson
            [nick_name] => jack
            [availability] => 1
            [is_fav] => 1
        )

    [1] => Array
        (
            [name] => David
            [nick_name] => dav07
            [availability] => 0
            [is_fav] => 1
        )

    [2] => Array
        (
            [name] => Zen
            [nick_name] => zen
            [availability] => 1
            [is_fav] => 0
        )

    [3] => Array
        (
            [name] => Rohit
            [nick_name] => rod
            [availability] => 0
            [is_fav] => 0
        )

    [4] => Array
        (
            [name] => Sally
            [nick_name] => sal
            [availability] => 0
            [is_fav] => 0
        )

)

PS) en utilisant strcmp serait une bonne option pour comparer les chaînes.

StudioX
la source