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


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


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

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

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'];
});

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
            )

    )

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.


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.


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


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 .


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

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.