Comment trier des tableaux et des données en PHP?

292

Cette question est destinée à servir de référence pour les questions sur le tri des tableaux en PHP. Il est facile de penser que votre cas particulier est unique et mérite une nouvelle question, mais la plupart sont en fait des variantes mineures de l'une des solutions de cette page.

Si votre question est fermée en tant que double de celle-ci, veuillez demander à ce que votre question ne soit rouverte que si vous pouvez expliquer pourquoi elle diffère sensiblement de toutes les réponses ci-dessous.

Comment trier un tableau en PHP?
Comment trier un tableau complexe en PHP?
Comment trier un tableau d'objets en PHP?


  1. Tableaux unidimensionnels de base; Incl. Tableaux multidimensionnels, incl. tableaux d'objets; Incl. Tri d'un tableau en fonction d'un autre

  2. Tri avec SPL

  3. Tri stable

Pour la réponse pratique en utilisant les fonctions existantes de PHP, voir 1., pour la réponse académique détaillée sur les algorithmes de tri (quelles fonctions PHP implémentent et dont vous pourriez avoir besoin pour des cas vraiment très complexes), voir 2.

décomposer
la source
@jterry Exactement, c'est pourquoi j'ai fait cela pour enfin avoir une bonne question de référence contre laquelle fermer. Répondre individuellement à chaque flocon de neige unique n'aide personne. :)
décomposer
3
Je pense que les gens devraient simplement jeter un œil à php.net
Alexander Jardim
@Alex Ha! Absolument. Le problème est: personne RTFM. : D
deceze
2
Nous avons déjà ces réponses, je vous suggère de lister les meilleures réponses dans chaque réponse ici au lieu de dupliquer (ou de réécrire) le contenu. Les tableaux ont également tendance à être vus individuellement, de sorte que le travail reste de près voter contre les dupes dans tous les cas.
hakre
1
@deceze: Si personne ne RTFM, personne ne sera également RTFQA - le Q & A existant :)
hakre

Réponses:

164

Tableaux unidimensionnels de base

$array = array(3, 5, 2, 8);

Fonctions de tri applicables:

  • sort
  • rsort
  • asort
  • arsort
  • natsort
  • natcasesort
  • ksort
  • krsort

La différence entre celles-ci est simplement de savoir si les associations de valeurs-clés sont conservées (les afonctions " "), si elles trient de bas en haut ou inversement (" r"), si elles trient des valeurs ou des clés (" k") et comment elles comparent les valeurs. (" nat" vs normal). Voir http://php.net/manual/en/array.sorting.php pour un aperçu et des liens vers plus de détails.

Tableaux multidimensionnels, y compris les tableaux d'objets

$array = array(
    array('foo' => 'bar', 'baz' => 42),
    array('foo' => ...,   'baz' => ...),
    ...
);

Si vous souhaitez trier $arraypar la clé 'foo' de chaque entrée, vous avez besoin d'une fonction de comparaison personnalisée . Les fonctions ci sort- dessus et connexes fonctionnent sur des valeurs simples qu'ils savent comparer et trier. PHP ne se contente pas de "savoir" quoi faire avec une valeur complexe comme array('foo' => 'bar', 'baz' => 42); vous devez donc le dire.

Pour ce faire, vous devez créer une fonction de comparaison . Cette fonction prend deux éléments et doit renvoyer 0si ces éléments sont considérés comme égaux, une valeur inférieure à 0si la première valeur est inférieure et une valeur supérieure à 0si la première valeur est supérieure. C'est tout ce qu'il faut:

function cmp(array $a, array $b) {
    if ($a['foo'] < $b['foo']) {
        return -1;
    } else if ($a['foo'] > $b['foo']) {
        return 1;
    } else {
        return 0;
    }
}

Souvent, vous souhaiterez utiliser une fonction anonyme comme rappel. Si vous souhaitez utiliser une méthode ou une méthode statique, consultez les autres façons de spécifier un rappel en PHP .

Vous utilisez ensuite l'une de ces fonctions:

Encore une fois, ils ne diffèrent que par le fait de conserver les associations clé-valeur et de les trier par valeurs ou clés. Lisez leur documentation pour plus de détails.

Exemple d'utilisation:

usort($array, 'cmp');

usortprendra deux éléments du tableau et appellera votre cmpfonction avec eux. Ainsi cmp()sera appelé avec $acomme array('foo' => 'bar', 'baz' => 42)et $bcomme un autre array('foo' => ..., 'baz' => ...). La fonction retourne ensuite à usortlaquelle des valeurs était la plus grande ou si elles étaient égales. usortrépète ce processus en passant différentes valeurs pour $aet $bjusqu'à ce que le tableau soit trié. La cmpfonction sera appelée plusieurs fois, au moins autant de fois qu'il y a de valeurs $array, avec différentes combinaisons de valeurs pour $aet à $bchaque fois.

Pour vous habituer à cette idée, essayez ceci:

function cmp($a, $b) {
    echo 'cmp called with $a:', PHP_EOL;
    var_dump($a);
    echo 'and $b:', PHP_EOL;
    var_dump($b);
}

Tout ce que vous avez fait était de définir une façon personnalisée de comparer deux articles, c'est tout ce dont vous avez besoin. Cela fonctionne avec toutes sortes de valeurs.

Soit dit en passant, cela fonctionne sur n'importe quelle valeur, les valeurs n'ont pas à être des tableaux complexes. Si vous souhaitez effectuer une comparaison personnalisée, vous pouvez également le faire sur un simple tableau de nombres.

sort trie par référence et ne renvoie rien d'utile!

Notez que le tableau est trié sur place , vous n'avez pas besoin d'attribuer la valeur de retour à quoi que ce soit. $array = sort($array)remplacera le tableau par true, pas par un tableau trié. Fonctionne juste sort($array);.

Comparaisons numériques personnalisées

Si vous souhaitez trier par la bazclé, qui est numérique, il vous suffit de:

function cmp(array $a, array $b) {
    return $a['baz'] - $b['baz'];
}

Grâce au PoWEr OF MATH, cela renvoie une valeur <0, 0 ou> 0 selon qu'elle $aest inférieure, égale ou supérieure à $b.

Notez que cela ne fonctionnera pas bien pour les floatvaleurs, car elles seront réduites à un intet perdront leur précision. Utilisez explicite -1, 0et les 1valeurs de retour à la place.

Objets

Si vous avez un tableau d'objets, cela fonctionne de la même manière:

function cmp($a, $b) {
    return $a->baz - $b->baz;
}

Les fonctions

Vous pouvez faire tout ce dont vous avez besoin dans une fonction de comparaison, y compris les fonctions d'appel:

function cmp(array $a, array $b) {
    return someFunction($a['baz']) - someFunction($b['baz']);
}

Cordes

Un raccourci pour la première version de comparaison de chaînes:

function cmp(array $a, array $b) {
    return strcmp($a['foo'], $b['foo']);
}

strcmpfait exactement ce qu'on attend d' cmpici, il revient -1, 0ou 1.

Opérateur de vaisseau spatial

PHP 7 a introduit l' opérateur de vaisseau spatial , qui unifie et simplifie égal / plus petit / plus grand que les comparaisons entre les types:

function cmp(array $a, array $b) {
    return $a['foo'] <=> $b['foo'];
}

Tri par plusieurs champs

Si vous souhaitez trier principalement par foo, mais si fooest égal pour deux éléments, trier par baz:

function cmp(array $a, array $b) {
    if (($cmp = strcmp($a['foo'], $b['foo'])) !== 0) {
        return $cmp;
    } else {
        return $a['baz'] - $b['baz'];
    }
}

Pour ceux qui le connaissent, cela équivaut à une requête SQL avec ORDER BY foo, baz.
Voir également cette version abrégée très soignée et comment créer dynamiquement une telle fonction de comparaison pour un nombre arbitraire de clés .

Tri dans un ordre manuel et statique

Si vous souhaitez trier les éléments dans un "ordre manuel" comme "foo", "bar", "baz" :

function cmp(array $a, array $b) {
    static $order = array('foo', 'bar', 'baz');
    return array_search($a['foo'], $order) - array_search($b['foo'], $order);
}

Pour tout ce qui précède, si vous utilisez PHP 5.3 ou supérieur (et vous devriez vraiment), utilisez des fonctions anonymes pour un code plus court et pour éviter d'avoir une autre fonction globale flottant:

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

Voilà comment le tri simple d'un tableau multidimensionnel complexe peut être. Encore une fois, pensez simplement en termes d' enseignement à PHP pour savoir lequel des deux éléments est "supérieur" ; laissez PHP faire le tri réel.

Aussi pour tout ce qui précède, pour basculer entre l'ordre croissant et décroissant, permutez simplement les arguments $aet $b. Par exemple:

return $a['baz'] - $b['baz']; // ascending
return $b['baz'] - $a['baz']; // descending

Tri d'un tableau en fonction d'un autre

Et puis il y a le particulier array_multisort, qui vous permet de trier un tableau en fonction d'un autre:

$array1 = array( 4,   6,   1);
$array2 = array('a', 'b', 'c');

Le résultat attendu ici serait:

$array2 = array('c', 'a', 'b');  // the sorted order of $array1

Utilisez array_multisortpour vous y rendre:

array_multisort($array1, $array2);

Depuis PHP 5.5.0, vous pouvez utiliser array_columnpour extraire une colonne d'un tableau multidimensionnel et trier le tableau sur cette colonne:

array_multisort(array_column($array, 'foo'), SORT_DESC, $array);

Depuis PHP 7.0.0, vous pouvez également extraire des propriétés d'un tableau d'objets.


Si vous avez des cas plus courants, n'hésitez pas à modifier cette réponse.

décomposer
la source
La fonction de comparaison numérique ne fonctionne pas pour les valeurs flottantes; Je suis sûr que vous savez de quoi je parle :)
Ja͢ck
1
Pour l'ordre statique, je demanderais array_flip()d'utiliser la recherche de position plus rapide, par exemple $order[$a['foo']]au lieu de array_search($a['foo'], $order).
Ja͢ck
Cela pourrait être un peu une grosse modification: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b mais si vous pensez que c'est une amélioration et que j'ai inclus tout ce qui est essentiel, je peux l'appliquer.
Rizier123
@ Rizier123 J'applaudis certainement l'effort, c'est un très bon résumé; mais je préférerais que vous le postiez comme réponse séparée, même si c'est très similaire. Votre réécriture contient beaucoup de détails (passage par référence, grand tableau, etc.), mais ce détail détourne l'attention de l'introduction en douceur au sujet central du fonctionnement de la fonction de comparaison, à mon humble avis. Je fais explicitement référence au manuel plusieurs fois à dessein, car c'est là que de tels détails doivent être recherchés; pas besoin de le répéter ici et de distraire de l'idée centrale que j'essaie de transmettre.
décomposer
@deceze Le principal défi, puisqu'il s'agit d'une Q&R de référence, est d'afficher les informations aussi compactes et lisibles que possible et de permettre aux utilisateurs de trouver facilement leur fonction de tri. J'ai modifié quelques éléments: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b mais je dois quand même y penser, s'il est utile et utile de le poster en tant que réponse séparée, car il s'agit d'un contenu très similaire
Rizier123
139

Eh bien, la plupart des méthodes de base sont déjà couvertes par la décomposition , j'essaierais d'examiner d'autres types de tri

Tri avec SPL

SplHeap

class SimpleHeapSort extends SplHeap {
    public function compare($a, $b) {
        return strcmp($a, $b);
    }
}

// Let's populate our heap here (data of 2009)
$heap = new SimpleHeapSort();
$heap->insert("a");
$heap->insert("b");
$heap->insert("c");

echo implode(PHP_EOL, iterator_to_array($heap));

Production

c
b
a

SplMaxHeap

La classe SplMaxHeap fournit les principales fonctionnalités d'un tas, en gardant le maximum au sommet.

$heap = new SplMaxHeap();
$heap->insert(1);
$heap->insert(2);
$heap->insert(3);

SplMinHeap

La classe SplMinHeap fournit les principales fonctionnalités d'un tas, en gardant le minimum en haut.

$heap = new SplMinHeap ();
$heap->insert(3);
$heap->insert(1);
$heap->insert(2);

Autres types de tri

Tri des bulles

De l'article Wikipedia sur Bubble Sort:

Le tri à bulles, parfois appelé à tort tri par enfoncement, est un algorithme de tri simple qui fonctionne en parcourant de manière répétée la liste à trier, en comparant chaque paire d'éléments adjacents et en les échangeant s'ils sont dans le mauvais ordre. Le passage dans la liste est répété jusqu'à ce qu'aucun échange ne soit nécessaire, ce qui indique que la liste est triée. L'algorithme tire son nom de la façon dont les éléments plus petits «bulle» en haut de la liste. Parce qu'il n'utilise que des comparaisons pour opérer sur des éléments, il s'agit d'un tri par comparaison. Bien que l'algorithme soit simple, la plupart des autres algorithmes de tri sont plus efficaces pour les grandes listes.

function bubbleSort(array $array) {
    $array_size = count($array);
    for($i = 0; $i < $array_size; $i ++) {
        for($j = 0; $j < $array_size; $j ++) {
            if ($array[$i] < $array[$j]) {
                $tem = $array[$i];
                $array[$i] = $array[$j];
                $array[$j] = $tem;
            }
        }
    }
    return $array;
}

Tri de sélection

Extrait de l'article Wikipédia sur le tri par sélection:

En informatique, le tri par sélection est un algorithme de tri, en particulier un tri par comparaison sur place. Il a une complexité temporelle O (n2), ce qui le rend inefficace sur les grandes listes et fonctionne généralement moins bien que le tri d'insertion similaire. Le tri par sélection est noté pour sa simplicité et présente des avantages en termes de performances par rapport à des algorithmes plus compliqués dans certaines situations, en particulier lorsque la mémoire auxiliaire est limitée.

function selectionSort(array $array) {
    $length = count($array);
    for($i = 0; $i < $length; $i ++) {
        $min = $i;
        for($j = $i + 1; $j < $length; $j ++) {
            if ($array[$j] < $array[$min]) {
                $min = $j;
            }
        }
        $tmp = $array[$min];
        $array[$min] = $array[$i];
        $array[$i] = $tmp;
    }
    return $array;
}

Tri par insertion

Extrait de l'article Wikipedia sur le tri par insertion:

Le tri par insertion est un algorithme de tri simple qui crée le tableau (ou la liste) trié final un élément à la fois. Il est beaucoup moins efficace sur les grandes listes que les algorithmes plus avancés tels que le tri rapide, le tri sélectif ou le tri par fusion. Cependant, le tri par insertion offre plusieurs avantages:

function insertionSort(array $array) {
    $count = count($array);
    for($i = 1; $i < $count; $i ++) {

        $j = $i - 1;
        // second element of the array
        $element = $array[$i];
        while ( $j >= 0 && $array[$j] > $element ) {
            $array[$j + 1] = $array[$j];
            $array[$j] = $element;
            $j = $j - 1;
        }
    }
    return $array;
}

Shellsort

De l'article Wikipedia sur Shellsort:

Shellsort, également connu sous le nom de Shell ou méthode de Shell, est un tri de comparaison sur place. Il généralise un tri d'échange, tel que l'insertion ou le tri à bulles, en commençant la comparaison et l'échange d'éléments avec des éléments éloignés avant de terminer avec des éléments voisins.

function shellSort(array $array) {
    $gaps = array(
            1,
            2,
            3,
            4,
            6
    );
    $gap = array_pop($gaps);
    $length = count($array);
    while ( $gap > 0 ) {
        for($i = $gap; $i < $length; $i ++) {
            $tmp = $array[$i];
            $j = $i;
            while ( $j >= $gap && $array[$j - $gap] > $tmp ) {
                $array[$j] = $array[$j - $gap];
                $j -= $gap;
            }
            $array[$j] = $tmp;
        }
        $gap = array_pop($gaps);
    }
    return $array;
}

Tri par peigne

Extrait de l'article Wikipédia sur le tri par peigne:

Le tri en peigne est un algorithme de tri relativement simple conçu à l'origine par Wlodzimierz Dobosiewicz en 1980. Plus tard, il a été redécouvert par Stephen Lacey et Richard Box en 1991. Le tri en peigne améliore le tri par bulles.

function combSort(array $array) {
    $gap = count($array);
    $swap = true;
    while ( $gap > 1 || $swap ) {
        if ($gap > 1)
            $gap /= 1.25;
        $swap = false;
        $i = 0;
        while ( $i + $gap < count($array) ) {
            if ($array[$i] > $array[$i + $gap]) {
                // swapping the elements.
                list($array[$i], $array[$i + $gap]) = array(
                        $array[$i + $gap],
                        $array[$i]
                );
                $swap = true;
            }
            $i ++;
        }
    }
    return $array;
}

Tri par fusion

De l'article Wikipedia sur le tri par fusion:

En informatique, un tri par fusion (également orthographié par fusion) est un algorithme de tri basé sur la comparaison O (n log n). La plupart des implémentations produisent un tri stable, ce qui signifie que l'implémentation préserve l'ordre d'entrée des éléments égaux dans la sortie triée

function mergeSort(array $array) {
    if (count($array) <= 1)
        return $array;

    $left = mergeSort(array_splice($array, floor(count($array) / 2)));
    $right = mergeSort($array);

    $result = array();

    while ( count($left) > 0 && count($right) > 0 ) {
        if ($left[0] <= $right[0]) {
            array_push($result, array_shift($left));
        } else {
            array_push($result, array_shift($right));
        }
    }
    while ( count($left) > 0 )
        array_push($result, array_shift($left));

    while ( count($right) > 0 )
        array_push($result, array_shift($right));

    return $result;
}

Tri rapide

Extrait de l'article Wikipedia sur Quicksort:

Quicksort, ou tri par échange de partitions, est un algorithme de tri développé par Tony Hoare qui, en moyenne, fait des comparaisons O (n log n) pour trier n éléments. Dans le pire des cas, il fait des comparaisons O (n2), bien que ce comportement soit rare.

function quickSort(array $array) {
    if (count($array) == 0) {
        return $array;
    }
    $pivot = $array[0];
    $left = $right = array();
    for($i = 1; $i < count($array); $i ++) {
        if ($array[$i] < $pivot) {
            $left[] = $array[$i];
        } else {
            $right[] = $array[$i];
        }
    }
    return array_merge(quickSort($left), array(
            $pivot
    ), quickSort($right));
}

Tri par permutation

Extrait de l'article Wikipedia sur le tri par permutation:

Tri par permutation, qui se déroule en générant les permutations possibles du tableau / liste d'entrée jusqu'à la découverte du tri trié.

function permutationSort($items, $perms = array()) {
    if (empty($items)) {
        if (inOrder($perms)) {
            return $perms;
        }
    } else {
        for($i = count($items) - 1; $i >= 0; -- $i) {
            $newitems = $items;
            $newperms = $perms;
            list($foo) = array_splice($newitems, $i, 1);
            array_unshift($newperms, $foo);
            $res = permutationSort($newitems, $newperms);
            if ($res) {
                return $res;
            }
        }
    }
}

function inOrder($array) {
    for($i = 0; $i < count($array); $i ++) {
        if (isset($array[$i + 1])) {
            if ($array[$i] > $array[$i + 1]) {
                return False;
            }
        }
    }
    return True;
}

Tri Radix

Extrait de l'article Wikipedia sur Radix sort:

En informatique, le tri radix est un algorithme de tri d'entiers non comparatif qui trie les données avec des clés entières en regroupant les clés par les chiffres individuels qui partagent la même position et valeur significatives.

// Radix Sort for 0 to 256
function radixSort($array) {
    $n = count($array);
    $partition = array();

    for($slot = 0; $slot < 256; ++ $slot) {
        $partition[] = array();
    }

    for($i = 0; $i < $n; ++ $i) {
        $partition[$array[$i]->age & 0xFF][] = &$array[$i];
    }

    $i = 0;

    for($slot = 0; $slot < 256; ++ $slot) {
        for($j = 0, $n = count($partition[$slot]); $j < $n; ++ $j) {
            $array[$i ++] = &$partition[$slot][$j];
        }
    }
    return $array;
}
Baba
la source
4
@deceze vous avez couvert toutes les bases .. j'ai dû chercher une autre façon d'être pertinent :)
Baba
5
Je ne vois rien de mal avec les méthodes de tri plus académiques :) beaucoup moins utiles pour la plupart des applications, mais parfois elles peuvent être demandées / requises est pratique d'avoir une référence d'autant plus que j'avais oublié la plupart d'entre elles au fil du temps
Dave
En fait, pour un tri rapide, il est recommandé de sélectionner pivot comme médiane de trois valeurs: premier, milieu et dernier éléments . Ceci est mon exemple de sélection de pivot. Cela permet d'éviter le pire des tableaux triés en sens inverse (ce qui provoque des O(n^2)comparaisons si nous utilisons uniquement le premier élément comme pivot)
Alma Do
J'ai entendu dire que spl fonctionne plus rapidement que le tri de tableaux normal.
jewelhuq
Je suis d'accord avec Dave, de nos jours, presque fw ont inclus pourquoi je m'en souviens ou l'utilise rarement.
Mike Nguyen
43

Tri stable

Disons que vous avez un tableau comme celui-ci:

['Kale', 'Kaleidoscope', 'Aardvark', 'Apple', 'Leicester', 'Lovely']

Et maintenant, vous voulez trier uniquement la première lettre:

usort($array, function($a, $b) {
    return strcmp($a[0], $b[0]);
});

Le résultat est le suivant:

['Apple', 'Aardvark', 'Kale', 'Kaleidoscope', 'Lovely', 'Leicester']

Le genre n'était pas stable!

L'observateur averti a peut-être remarqué que l'algorithme de tri de tableau (QuickSort) n'a pas produit de résultat stable et que l'ordre d'origine entre les mots de la même première lettre n'a pas été conservé. Ce cas est trivial et nous aurions dû comparer la chaîne entière, mais supposons que votre cas d'utilisation soit plus compliqué, comme deux tris consécutifs sur des champs différents qui ne devraient pas s'annuler mutuellement.

La transformation schwartzienne

La transformée de Schwartzian , également appelée idiome décorer-trier-décorer, effectue un tri stable avec un algorithme de tri intrinsèquement instable.

Tout d'abord, vous décorez chaque élément du tableau avec un autre tableau comprenant une clé primaire (la valeur) et une clé secondaire (son index ou sa position):

array_walk($array, function(&$element, $index) {
    $element = array($element, $index); // decorate
});

Cela transforme le tableau en ceci:

[
    ['Kale', 0], ['Kaleidoscope', 1], 
    ['Aardvark', 2], ['Apple', 3], 
    ['Leicester', 4], ['Lovely', 5]
]

Maintenant, nous ajustons l'étape de comparaison; nous comparons à nouveau la première lettre, mais si elles sont identiques, la clé secondaire est utilisée pour conserver l'ordre d'origine:

usort($array, function($a, $b) {
    // $a[0] and $b[0] contain the primary sort key
    // $a[1] and $b[1] contain the secondary sort key
    $tmp = strcmp($a[0][0], $b[0][0]);

    if ($tmp != 0) {
        return $tmp; // use primary key comparison results
    }

    return $a[1] - $b[1]; // use secondary key
});

Ensuite, on décore:

array_walk($array, function(&$element) {
    $element = $element[0];
});

Le résultat final:

['Aardvark', 'Apple', 'Kale', 'Kaleidoscope', 'Leicester', 'Lovely']

Et la réutilisation?

Vous avez dû réécrire votre fonction de comparaison pour travailler avec les éléments de tableau transformés; vous ne voudrez peut-être pas modifier vos fonctions de comparaison délicates, alors voici un wrapper pour la fonction de comparaison:

function stablecmp($fn)
{
    return function($a, $b) use ($fn) {
        if (($tmp = call_user_func($fn, $a[0], $b[0])) != 0) {
            return $tmp;
        } else {
            return $a[1] - $b[1];
        }
    };
}

Écrivons l'étape de tri à l'aide de cette fonction:

usort($array, stablecmp(function($a, $b) {
    return strcmp($a[0], $b[0]);
}));

Voila! Votre code de comparaison vierge est de retour.

Jack
la source
Votre phrase "effectue un tri stable avec un algorithme de tri intrinsèquement instable" a été le moment ah-ha pour moi. La page wikipedia ne fait aucune mention du mot stable, qui me semble être la beauté de la transformation. La honte.
Tyler Collier
1
@TylerCollier Oui, vous devez lire entre les lignes de cette référence Wikipédia ... Je vous ai évité de le faire ;-)
Ja͢ck
15

Depuis PHP 5.3 avec fermetures, il est également possible d'utiliser une fermeture pour déterminer l'ordre de votre tri.

Par exemple, en supposant que $ array est un tableau d'objets qui contiennent une propriété month.

 $orderArray = array("Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec");

 usort($array, function($a, $b) use ($orderArray){
       return array_search($a->month, $orderArray) - array_search($b->month, $orderArray);
 }); 
Orangepill
la source
N'oubliez pas que cela supprimera tout ordre relatif précédent (par exemple, le premier objet "July" dans la liste pré-triée peut se retrouver à la fin du groupe d'objets July après le tri). Voir "Tri stable" ci-dessus.
George Langley
9

LINQ

Dans .NET, LINQ est fréquemment utilisé pour le tri, qui fournit une syntaxe beaucoup plus agréable que les fonctions de comparaison, en particulier lorsque les objets doivent être triés par plusieurs champs. Il existe plusieurs ports de LINQ vers PHP, y compris la bibliothèque YaLinqo *. Avec lui, les tableaux peuvent être triés sur une seule ligne sans écrire de fonctions de comparaison complexes.

$sortedByName         = from($objects)->orderBy('$v->name');
$sortedByCount        = from($objects)->orderBy('$v->count');
$sortedByCountAndName = from($objects)->orderBy('$v->count')->thenBy('$v->name');

Les comparaisons peuvent être personnalisées davantage en passant un rappel comme deuxième argument, par exemple:

$sortedByFilenameNat  = from($objects)->orderBy('$v->filename', 'strnatcmp');

Voici '$v->count'un raccourci pour function ($v) { return $v->count; }(l'un ou l'autre peut être utilisé). Ces chaînes de méthodes renvoient des itérateurs, les itérateurs peuvent être transformés en tableaux en ajoutant ->toArray()à la fin si nécessaire.

En interne, orderByet des méthodes connexes appellent tableau appropriées fonctions de tri ( uasort, krsort, multisort, usortetc.).

LINQ contient de nombreuses autres méthodes inspirées de SQL: filtrage, regroupement, jointure, agrégation, etc. Il convient mieux aux cas où des transformations complexes sur des tableaux et des objets doivent être effectuées sans s'appuyer sur des bases de données.

* développé par mes soins, consultez le fichier Lisez-moi pour plus de détails et une comparaison avec d'autres ports LINQ

Athari
la source
3

Tri multidimensionnel par valeur de clé

Tri naturel d'un tableau multidimensionnel par valeur de clé et conserve également l'ordre d'origine (ne mélangez pas les clés principales):

function multisortByKeyValue( $k, $arr ) {
    $ids   = array();
    $index = 1;

    foreach ( $arr as $key => $row ) {
        $ids[ $key ] = intval( $row[ $k ] ) . '-' . $index . '-' . $key;
        $index ++;
    }

    natsort( $ids );

    $arr = array_merge( $ids, $arr );

    return $arr;
}

Cas de test:

$arr = array(
    'id1' => array(
        'label'    => 'ID 1',
        'priority' => 30,
    ),
    'id2' => array(
        'label'    => 'ID 2',
        'priority' => 70,
    ),
    'id3' => array(
        'label'    => 'ID 3',
        'priority' => 20,
    ),
    'id4' => array(
        'label'    => 'ID 4',
        'priority' => 30,
    ),
);

$sorted = multisortByKeyValue( 'priority', $arr );

// $sorted equals to:
/*
array (
  'id3' => array (
    'label' => 'ID 3',
    'priority' => 20,
  ),
  'id1' => array (
    'label' => 'ID 1',
    'priority' => 30,
  ),
  'id4' => array (
    'label' => 'ID 4',
    'priority' => 30,
  ),
  'id2' => array (
    'label' => 'ID 2',
    'priority' => 70,
  ),
)
*/
Andrew Surdu
la source
2

Il est très pratique de trier les tableaux avec la fonction triée de Nspl :

Tri de base

// Sort array
$sorted = sorted([3, 1, 2]);

// Sort array in descending order
$sortedDesc = sorted([3, 1, 2], true);

Tri par résultat de fonction

// Sort array by the result of a given function (order words by length)
$sortedByLength = sorted(['bc', 'a', 'abc'], 'strlen');
$sortedByLengthDesc = sorted(['bc', 'a', 'abc'], true, 'strlen');

// Sort array by the result of user-defined function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], function($v) { return $v[0]; }); 

// Which is the same as
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], itemGetter(0));
$sortedByTheFirstCharacterDesc = sorted(['bc', 'a', 'abc'], true, itemGetter(0));

// itemGetter(0) returns a function which takes an argument with access by index/key
// and returns the value at index 0

Tri du tableau multidimensionnel

// Sort multidimensional array (sort list of users by their names)
$users = [
    array('name' => 'Robert', 'age' => 20),
    array('name' => 'Alex', 'age' => 30),
    array('name' => 'Jack', 'age' => 25),
];
$sortedByName = sorted($users, itemGetter('name'));
$sortedByNameDesc = sorted($users, true, itemGetter('name'));

// itemGetter('name') returns a function which takes an argument with access by index/key
// and returns the value of the 'name' key

Tri d'un tableau d'objets

// Lets assume we have class User(name, age) with properties name and age
// and public methods getName() and getAge()
$users = [
    new User('Robert', 20),
    new User('Alex', 30),
    new User('Jack', 25),
];

// Sort list of objects by property value (sort list of users by their name)
$sortedByName = sorted($users, propertyGetter('name'));
$sortedByNameDesc = sorted($users, true, propertyGetter('name'));

// propertyGetter('name') returns a function which takes an object
// and returns the value of its 'name' property

// Sort list of objects by method result (sort list of users by their age)
$sortedByAge = sorted($users, methodCaller('getAge'));
$sortedByAgeDesc = sorted($users, true, methodCaller('getAge'));

// methodCaller('getAge') returns a function which takes an object
// and returns the result of its getAge() method

Tri avec fonction de comparaison

// Sort with a comparison function (order words lexicographically with strcmp)
$sortedLexicographically = sorted(['bc', 'a', 'abc'], false, null, 'strcmp');

// Sort with user-defined comparison function (order words by the 1st character)
$sortedByTheFirstCharacter = sorted(['bc', 'a', 'abc'], false, null, function($v1, $v2) {
    return chr($v1[0]) - chr($v2[0]);
});

Vous pouvez voir tous ces exemples ici .

Ihor Burlachenko
la source
2

Si vous souhaitez commander par valeur clé, vous pouvez le faire sur une ligne, élégante et claire. Cette commande se fera par le prix croissant. Utilise array_multisort et array_column.

   Array([0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => coffee [price] => 9.99 ) [2] => Array ( [name] => rice [price] => 4.04 ) )

   array_multisort (array_column($array, 'price'), SORT_ASC, $array);

produire

     Array ( [0] => Array ( [name] => eggs [price] => 1 ) [1] => Array ( [name] => rice [price] => 4.04 ) [2] => Array ( [name] => coffee [price] => 9.99 ) )
GAV
la source
1

Cette page est très complète, mais je veux ajouter un peu plus sur l'utilité impressionnante de l'opérateur de vaisseau spatial (opérateur de comparaison à trois voies) - un bel enfant de PHP7 +.

Utilisation de l'opérateur de vaisseau spatial pour implémenter plusieurs conditions de tri

Cela fait de grands progrès dans la réduction du gonflement du code et l'amélioration de la lisibilité.

Lorsque vous écrivez votre fonction de tri personnalisé ( usort()/ uasort()/ uksort()) pour traiter plusieurs conditions, il vous suffit d'écrire des tableaux équilibrés de chaque côté de l'opérateur et de renvoyer le résultat. Plus de blocs de condition imbriqués ni de retours multiples.

Les éléments des deux côtés de l'opérateur seront parcourus de gauche à droite, un par un, et retournant l'évaluation dès qu'une non-liaison est rencontrée ou lorsque les éléments ont tous été comparés.

Exemples de données pour mes démonstrations:

$multidimArray = [
    'a' => [
        'boolean' => true,
        'natString' => 'text10',
        'object' => (object)['prop' => 2],
        'float' => -.5,
        'mixed' => []
    ],
    'b' => [
        'boolean' => true,
        'natString' => 'text12',
        'object' => (object)['prop' => 4],
        'float' => 0,
        'mixed' => null
    ],
    'c' => [
        'boolean' => false,
        'natString' => 'text100',
        'object' => (object)['prop' => 9],
        'float' => -.5,
        'mixed' => false
    ],
    'd' => [
        'boolean' => true,
        'natString' => 'text1',
        'object' => (object)['prop' => 9],
        'float' => -5,
        'mixed' => "\0"
    ],
    'e' => [
        'boolean' => false,
        'natString' => 'text2',
        'object' => (object)['prop' => 2],
        'float' => .5,
        'mixed' => ''
    ]
];

Démonstrations (pour éviter le gonflement de la page Stackoverflow, veuillez consulter le lien de démonstration pour les sorties):

  • Logique de tri:

    1. DESC booléen (faux = 0, vrai = 1, donc vrai avant faux)
    2. flotteur ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
  • Logique de tri:

    1. ASC mixte
    2. objet ASC
    3. ASC booléen

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
  • Logique de tri:

    1. nombre de propriétés de l'objet ASC
    2. itérabilité du DESC mixte
    3. natString length ASC
    4. natString ASC

      uasort($multidimArray, function($a, $b) {
          return [count(get_object_vars($a['object'])), is_iterable($a['mixed']), strlen($a['natString']), $a['natString']]
                 <=>
                 [count(get_object_vars($b['object'])), is_iterable($b['mixed']), strlen($b['natString']), $b['natString']];
      });

Cette syntaxe vous permet de trier les valeurs, les résultats fonctionnels, les données profondément imbriquées et la direction de tri d'une manière élégante. Cela vaut vraiment la peine de mettre votre ceinture d'outils php ... pour les cas où vous traitez des données non liées à une base de données - car bien sûr, SQL serait une technique beaucoup plus judicieuse.

À votre propre discrétion, à partir de PHP7.4, vous pouvez utiliser la syntaxe des flèches avec ces fonctions anonymes. Même script avec la syntaxe des flèches .

mickmackusa
la source
0

Si quelqu'un veut une solution plus simple pour manipuler les tableaux, utilisez simplement le package Laravel Collection qui a une fonction sortBy implémentée qui permet de trier simplement par clés.

$collection->sortBy('forename')->sortBy('surname');

c'est-à-dire, afin de trier d'abord par a, puis b, puis c, la bonne clause serait

sortBy('c')->sortBy('b')->sortBy('a')

https://packagist.org/packages/tightenco/collect

Rizerzero
la source
-1

Il y a plusieurs façons de trier un tableau.Je mentionnerai quelques méthodes pour faire cette tâche.Pour commencer, je donnerai un tableau entier qui s'appelle '$ nombres'.

$number = array(8,9,3,4,0,1,2);

C'est la manière normale de créer un tableau. Supposons que je veuille trier ce tableau dans l'ordre croissant, pour cela, la méthode 'sort ()' peut être utilisée.

<?php

    $number = array(8,9,3,4,0,1,2);
    sort($number);

   foreach ($number as $value) {
       echo $value."  ";
   }
?>

Considérez maintenant la sortie de cela,

entrez la description de l'image ici

Vous pouvez voir que le tableau des numéros imprimés est trié. Si vous voulez que ce tableau de nombres soit trié par ordre décroissant, la méthode 'rsort ()' peut être utilisée pour cette tâche.

<?php

     $number = array(8,9,3,4,0,1,2);
     rsort($number);

     foreach ($number as $value) {
        echo $value."  ";
     }
?>

considérer la sortie ..

entrez la description de l'image ici

Maintenant, le tableau est trié dans l'ordre décroissant.Ok, considérons un tableau associatif.Je donnerai un tableau associatif (tableau associatif signifie que, un tableau dont chaque index a une valeur de clé unique.) Comme ceci,

$number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);

Donc, maintenant je veux trier ce tableau dans l'ordre croissant en fonction de leur valeur. La méthode 'asort ()' peut être utilisée pour cela.

<?php

   $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
   asort($number);

   foreach ($number as $value) {
      echo $value."  ";
    }
?>

Si vous triez l'ordre décroissant en fonction de leur valeur, la méthode 'arsort ()' peut être utilisée. Supposons que vous souhaitiez trier ce tableau en fonction de leur valeur de clé. Dans ce cas, la méthode 'ksort ()' peut être utilisée.

<?php

     $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
     ksort($number);

     foreach ($number as $value) {
         echo $value."  ";
     }
?>

Considérez maintenant la sortie. entrez la description de l'image ici

Le tableau est maintenant trié en fonction de sa valeur de clé.Si vous souhaitez trier le tableau en ordre décroissant en fonction de sa valeur de clé, la méthode 'krsort ()' peut être utilisée.

<?php

    $number = array('eight'=>8,'nine'=>9,'three'=>3,'fore'=>4,'zero'=>0,'one'=>1,'two'=>2);
    krsort($number);

    foreach ($number as $value) {
       echo $value."  ";
    }
?>

Maintenant, le tableau associatif est trié par ordre décroissant en fonction de leur valeur de clé. entrez la description de l'image ici

Ce sont les quelques méthodes pour trier un tableau dans l'ordre croissant ou décroissant en php.J'espère que vous pourriez avoir une idée.Merci!

GT_hash
la source
Deceze ne couvre pas déjà ces informations avec: "La différence entre celles-ci est simplement de savoir si les associations de valeurs-clés sont conservées (les fonctions" a "), si elles trient de bas en haut ou inversement (" r "), si elles trie les valeurs ou les clés ("k") et comment il compare les valeurs ("nat" par rapport à la normale). " dans la réponse acceptée?
mickmackusa
-2

Le plus simple est d'utiliser la fonction usort pour trier les tableaux sans boucle: voici un exemple:

   $array_compare= array("0" =>4,"1"=>2,"2"=>500,"3"=>100);

Cela triera par ordre décroissant:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) > 0 ? 1 :-1;
    });

Cela triera dans l'ordre suivant:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) < 0 ? 1 :-1;
    });
pihu
la source
1
1) L'exemple et le code sont incohérents. 2) Ceci est déjà expliqué en détail atroce dans les réponses ci-dessus. 3) Essayez-vous éventuellement de répondre à une autre question?
décomposition