PHP Trier le tableau par valeur de sous-tableau

110

J'ai la structure de tableau suivante:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )

Quelle est la meilleure façon d'ordonner le tableau de manière incrémentielle, en fonction du optionNumber?

Les résultats ressemblent donc à:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )
Sjwdavies
la source

Réponses:

204

Utilisez usort.

function cmp_by_optionNumber($a, $b) {
  return $a["optionNumber"] - $b["optionNumber"];
}

...

usort($array, "cmp_by_optionNumber");

En PHP ≥5.3, vous devriez utiliser une fonction anonyme à la place:

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

Notez que les deux codes ci-dessus supposent qu'il $a['optionNumber']s'agit d'un entier. Utilisez @St. La solution de John Johnson si ce sont des chaînes.


En PHP ≥7.0, utilisez l' opérateur<=> du vaisseau spatial au lieu de la soustraction pour éviter les problèmes de débordement / troncature.

usort($array, function ($a, $b) {
    return $a['optionNumber'] <=> $b['optionNumber'];
});
KennyTM
la source
1
Cela ne m'aide pas vraiment car l'usort exige que je lui fournisse une fonction à utiliser - ce qui est la partie difficile que je ne peux pas comprendre
Sjwdavies
17
Eh bien, il vous a juste donné la fonction à utiliser. Et vous allez devoir accepter qu'il n'y a pas toujours une fonction intégrée pour faire ce que vous voulez, vous devez l'écrire vous-même. Les fonctions de comparaison nécessitent simplement un retour de 1, 0 ou -1 indiquant l'ordre de tri de deux éléments.
Tesserex
1
J'ai regardé plus loin dans usort et c'est en fait assez cool. J'ai écrit une simple fonction de comparaison avec celle ci-dessus, mais j'ai manqué le '=='. Merci pour l'aide les gars
Sjwdavies
3
Maintenant aussi comme fermeture: - usort ($ array, function ($ a, $ b) {return $ b ["optionNumber"] - $ a ["optionNumber"];});
Joeri
1
@ KiloumapL'artélon Si le résultat est < 0, il indique la fonction de tri qui adoit apparaître avant b. Si elle est > 0alors bdevrait apparaître avant a.
kennytm
57

Utilisation usort

 usort($array, 'sortByOption');
 function sortByOption($a, $b) {
   return strcmp($a['optionNumber'], $b['optionNumber']);
 }
St. John Johnson
la source
7
@BenSinclair, c'est parce que la solution de Kenny est pour les nombres, cette solution est pour les chaînes. Ils sont tous les deux corrects :-) +1 pour cette alternative.
kubilay
Pour un tri insensible à la casse, utilisez strcasecmp au lieu de strcmp
user570605
pouvons-nous définir la clé pour le deuxième ordre dans le tableau signifie que nous faisons d'abord un tri avec optionNumber puis un tri avec lastUpdated. Comment faire ça?
Bhavin Thummar
16

J'ai utilisé les deux solutions de KennyTM et AJ Quick et j'ai proposé une fonction qui peut aider dans ce problème dans de nombreux cas, comme l' utilisation du tri ASC ou DESC ou la préservation des clés ou si vous avez des objets comme enfants de array .

Voici cette fonction (fonctionne pour PHP7 et supérieur à cause de l'opérateur du vaisseau spatial):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if ($preserveKeys) {
        $c = [];
        if (is_object(reset($array))) {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v->$value);
            }
        } else {
            foreach ($array as $k => $v) {
                $b[$k] = strtolower($v[$value]);
            }
        }
        $asc ? asort($b) : arsort($b);
        foreach ($b as $k => $v) {
            $c[$k] = $array[$k];
        }
        $array = $c;
    } else {
        if (is_object(reset($array))) {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
            });
        } else {
            usort($array, function ($a, $b) use ($value, $asc) {
                return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
            });
        }
    }

    return $array;
}

Usage:

sortBySubValue($array, 'optionNumber', true, false);

Éditer

La première partie peut être réécrite en utilisant uasort()et la fonction sera plus courte (fonctionne pour PHP7 et plus à cause de l'opérateur du vaisseau spatial):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)
{
    if (is_object(reset($array))) {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a->{$value} == $b->{$value} ? 0 : ($a->{$value} <=> $b->{$value}) * ($asc ? 1 : -1);
        });
    } else {
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        }) : usort($array, function ($a, $b) use ($value, $asc) {
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        });
    }
    return $array;
}
Pigalev Pavel
la source
C'est la meilleure réponse la plus utile ici, devrait être en haut;)
Edi Budimilic
@EdiBudimilic merci, je l'apprécie! Au fait, j'ai mis à jour ma réponse et ajouté une version plus courte de cette fonction :)
Pigalev Pavel
1
Pour que cela fonctionne pour moi, j'ai dû utiliser >(supérieur à) au lieu de -(moins) lors de la comparaison $aet des $bvaleurs puisque je comparais des chaînes. Fonctionne toujours cependant.
James
1
@James vous avez raison. J'ai changé la réponse et ajouté l'utilisation de l'opérateur de vaisseau spatial (<=>). Maintenant, cela devrait fonctionner correctement.
Pigalev Pavel
Existe-t-il un moyen de rendre ce cas insensible?
loeffel
4

Les touches sont supprimées lors de l'utilisation d'une fonction comme celles ci-dessus. Si les touches sont importantes, la fonction suivante la maintiendra ... mais les boucles foreach sont assez inefficaces.

function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[$key] = $a[$key];
    }
    return $c;
}
$array = subval_sort($array,'optionNumber');

Utilisez arsort au lieu de asort si vous voulez du haut vers le bas.

Crédit de code: http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/

AJ rapide
la source
4

Utilisation de array_multisort (), array_map ()

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

print_r($array);

DEMO

Ghanshyam Nakiya
la source
2
Cela fonctionne très facilement. Je vous remercie. Tout ce que j'avais à faire était de changer le nom de ma colonne et cela a fonctionné.
Kobus Myburgh
2
Cela préserve également les clés du tableau parent
JonnyS
3

PHP 5.3+

usort($array, function($a,$b){ return $a['optionNumber']-$b['optionNumber'];} );
Samer Ata
la source