Comment trier un tableau de tableaux associatifs en valeur d'une clé donnée en PHP?

étant donné ce tableau:

$inventory = array(

   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),
   array("type"=>"pork", "price"=>5.43),

);

je voudrais trier $inventory éléments par le prix pour obtenir:

$inventory = array(

   array("type"=>"pork", "price"=>5.43),
   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),

);

Comment faire?

313
demandé sur Mark Amery 2009-10-21 02:47:26

16 réponses

vous avez raison, la fonction que vous recherchez est array_multisort() .

voici un exemple tiré directement du manuel et adapté à votre cas:

$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);
448
répondu Josh Davis 2014-03-20 15:40:47

PHP 7+

à partir de PHP 7, cela peut être fait concise en utilisant usort avec une fonction anonyme qui utilise le opérateur de vaisseau spatial pour comparer des éléments.

vous pouvez faire un Tri ascendant comme ceci:

usort($inventory, function ($item1, $item2) {
    return $item1['price'] <=> $item2['price'];
});

ou une sorte descendante comme celle-ci:

usort($inventory, function ($item1, $item2) {
    return $item2['price'] <=> $item1['price'];
});

Pour comprendre comment cela fonctionne, notez que usort prend une fonction de comparaison fournie par l'utilisateur qui doit se comporter comme suit (à partir du docs):

La fonction de comparaison doit retourner un entier inférieur, égal ou supérieur à zéro si le premier argument est respectivement inférieure, égale, ou supérieure à la seconde.

et noter également que <=> , l'opérateur du vaisseau spatial,

renvoie 0 si les deux opérandes sont égales, 1 si la gauche est plus grande, et -1 si la droite est plus grande

ce qui est exactement ce dont usort a besoin. En fait, presque toute la justification donnée pour ajouter <=> au langage dans https://wiki.php.net/rfc/combined-comparison-operator est qu'il

rend l'écriture de commandes de callbacks pour une utilisation avec usort() plus facile


PHP 5.3+

PHP 5.3 introduit des fonctions anonymes, mais n'a pas encore l'opérateur du vaisseau spatial. Nous pouvons toujours utiliser usort pour trier notre tableau, mais c'est un peu plus verbeux et plus difficile à comprendre:

usort($inventory, function ($item1, $item2) {
    if ($item1['price'] == $item2['price']) return 0;
    return $item1['price'] < $item2['price'] ? -1 : 1;
});

noter que bien qu'il soit assez commun pour les comparateurs traitant des valeurs entières de simplement retourner la différence des valeurs, comme $item2['price'] - $item1['price'] , nous ne peut pas en toute sécurité faire cela dans ce cas. C'est parce que les prix sont des nombres à virgule flottante dans l'exemple d'asker de question, mais la fonction de comparaison que nous passons à usort doit retourner des entiers pour usort pour fonctionner correctement:

Returning non-integer les valeurs de la fonction de comparaison, telles que float, résulteront en un plâtre interne à l'entier de la valeur de retour de l'appel. Ainsi les valeurs telles que 0.99 et 0.1 seront toutes les deux coulées à une valeur entière de 0, qui comparera de telles valeurs comme égale.

c'est un piège important à garder à l'esprit lors de l'utilisation de usort en PHP 5.x! ma version originale de cette réponse a fait cette erreur et pourtant j'ai accumulé dix upvotes sur des milliers de vues apparemment sans que personne ne s'en aperçoive. La facilité avec laquelle les idiots comme moi peuvent faire foirer les fonctions de comparaison est précisément la raison pour laquelle l'opérateur de vaisseau spatial plus facile à utiliser a été ajouté au langage en PHP 7.

189
répondu Mark Amery 2017-05-23 11:47:17

puisque vos éléments de tableau sont des tableaux eux-mêmes avec des clés de chaîne, votre meilleur pari est de définir une fonction de comparaison personnalisée. C'est assez rapide et facile à faire. Essayez ceci:

function invenDescSort($item1,$item2)
{
    if ($item1['price'] == $item2['price']) return 0;
    return ($item1['price'] < $item2['price']) ? 1 : -1;
}
usort($inventory,'invenDescSort');
print_r($inventory);

produit ce qui suit:

Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

    [1] => Array
        (
            [type] => fruit
            [price] => 3.5
        )

    [2] => Array
        (
            [type] => milk
            [price] => 2.9
        )

)
39
répondu zombat 2009-10-20 23:04:35

alors que d'autres ont suggéré à juste titre l'utilisation de array_multisort() , pour certaines raisons aucune réponse ne semble reconnaître l'existence de array_column() , ce qui peut grandement simplifier la solution. Donc ma suggestion serait:

array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);
30
répondu Mariano Iglesias 2017-03-28 21:04:19

j'ai terminé sur ceci:

function sort_array_of_array(&$array, $subfield)
{
    $sortarray = array();
    foreach ($array as $key => $row)
    {
        $sortarray[$key] = $row[$subfield];
    }

    array_multisort($sortarray, SORT_ASC, $array);
}

il suffit d'appeler la fonction, en passant le tableau et le nom de domaine de deuxième niveau tableau. Comme:

sort_array_of_array($inventory, 'price');
21
répondu Danielzt 2013-12-19 15:18:23

vous pouvez utiliser usort avec une fonction anonyme, par exemple

usort($inventory, function ($a, $b) { return strnatcmp($a['price'], $b['price']); });
12
répondu kenorb 2016-08-30 16:16:09
$inventory = 
    array(array("type"=>"fruit", "price"=>3.50),
          array("type"=>"milk", "price"=>2.90),
          array("type"=>"pork", "price"=>5.43),
          );

function pricesort($a, $b) {
  $a = $a['price'];
  $b = $b['price'];
  if ($a == $b)
    return 0;
  return ($a > $b) ? -1 : 1;
}

usort($inventory, "pricesort");
// uksort($inventory, "pricesort");

print("first: ".$inventory[0]['type']."\n\n");
// for usort(): prints milk (item with lowest price)
// for uksort(): prints fruit (item with key 0 in the original $inventory)

// foreach prints the same for usort and uksort.
foreach($inventory as $i){
  print($i['type'].": ".$i['price']."\n");
}

sorties:

first: pork

pork: 5.43
fruit: 3.5
milk: 2.9
8
répondu danamlund 2009-10-20 23:16:21

a été testé sur 100 000 enregistrements: Temps en secondes (calculé par funciton microtime). uniquement pour les valeurs uniques sur le tri des positions clés.

Solution de fonction de @ Josh Davis: Spended temps : 1.5768740177155

solution de Mine: Spended temps : 0.094044923782349

Solution:

function SortByKeyValue($data, $sortKey, $sort_flags=SORT_ASC)
{
    if (empty($data) or empty($sortKey)) return $data;

    $ordered = array();
    foreach ($data as $key => $value)
        $ordered[$value[$sortKey]] = $value;

    ksort($ordered, $sort_flags);

    return array_values($ordered); *// array_values() added for identical result with multisort*
}
3
répondu Nefelim 2013-05-15 11:39:33

vous pourriez essayer de définir votre propre fonction de comparaison et ensuite utiliser usort .

1
répondu Alex Sexton 2009-10-20 23:07:00

cette fonction est réutilisable:

function usortarr(&$array, $key, $callback = 'strnatcasecmp') {
    uasort($array, function($a, $b) use($key, $callback) {
        return call_user_func($callback, $a[$key], $b[$key]);
    });
}

cela fonctionne bien sur les valeurs de chaîne de caractères par défaut, mais vous devrez soumettre la callback pour une fonction de comparaison de nombre si toutes vos valeurs sont des nombres.

1
répondu mpen 2017-05-23 12:18:17

à Partir de Tri d'un tableau de tableaux associatifs par la valeur de la clé donnée en php :

uasort ( http://php.net/uasort ) vous permet de trier un tableau par votre propre fonction définie. Dans votre cas, c'est simple:

$array = array(
  array('price'=>'1000.50','product'=>'test1'),
  array('price'=>'8800.50','product'=>'test2'),
  array('price'=>'200.0','product'=>'test3')
);

function cmp($a, $b) {
  return $a['price'] > $b['price'];
}

uasort($array, "cmp");
1
répondu Kamal 2018-04-11 21:04:48
//Just in one line custom function
function cmp($a, $b)
{
return (float) $a['price'] < (float)$b['price'];
}
@uasort($inventory, "cmp");
print_r($inventory);

//result

Array
(
[2] => Array
    (
        [type] => pork
        [price] => 5.43
    )

[0] => Array
    (
        [type] => fruit
        [price] => 3.5
    )

[1] => Array
    (
        [type] => milk
        [price] => 2.9
    )

)
0
répondu Kamal 2014-09-20 07:15:24

Dynamique Complète De La Fonction J'ai sauté ici pour le tri associative array et j'ai trouvé cette fonction étonnante sur http://php.net/manual/en/function.sort.php . Cette fonction est très dynamique qui trient dans l'ordre croissant et décroissant avec la clé spécifiée.

fonction Simple pour trier un tableau par une clé spécifique. Maintient de l'indice de l'association

<?php

function array_sort($array, $on, $order=SORT_ASC)
{
    $new_array = array();
    $sortable_array = array();

    if (count($array) > 0) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                foreach ($v as $k2 => $v2) {
                    if ($k2 == $on) {
                        $sortable_array[$k] = $v2;
                    }
                }
            } else {
                $sortable_array[$k] = $v;
            }
        }

        switch ($order) {
            case SORT_ASC:
                asort($sortable_array);
            break;
            case SORT_DESC:
                arsort($sortable_array);
            break;
        }

        foreach ($sortable_array as $k => $v) {
            $new_array[$k] = $array[$k];
        }
    }

    return $new_array;
}

$people = array(
    12345 => array(
        'id' => 12345,
        'first_name' => 'Joe',
        'surname' => 'Bloggs',
        'age' => 23,
        'sex' => 'm'
    ),
    12346 => array(
        'id' => 12346,
        'first_name' => 'Adam',
        'surname' => 'Smith',
        'age' => 18,
        'sex' => 'm'
    ),
    12347 => array(
        'id' => 12347,
        'first_name' => 'Amy',
        'surname' => 'Jones',
        'age' => 21,
        'sex' => 'f'
    )
);

print_r(array_sort($people, 'age', SORT_DESC)); // Sort by oldest first
print_r(array_sort($people, 'surname', SORT_ASC)); // Sort by surname
0
répondu Ahmad Sayeed 2017-09-29 14:27:14
$arr1 = array(

    array('id'=>1,'name'=>'aA','cat'=>'cc'),
    array('id'=>2,'name'=>'aa','cat'=>'dd'),
    array('id'=>3,'name'=>'bb','cat'=>'cc'),
    array('id'=>4,'name'=>'bb','cat'=>'dd')
);

$result1 = array_msort($arr1, array('name'=>SORT_DESC);

$result2 = array_msort($arr1, array('cat'=>SORT_ASC);

$result3 = array_msort($arr1, array('name'=>SORT_DESC, 'cat'=>SORT_ASC));


function array_msort($array, $cols)
{
    $colarr = array();
    foreach ($cols as $col => $order) {
    $colarr[$col] = array();
    foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}

$eval = 'array_multisort(';

foreach ($cols as $col => $order) {
    $eval .= '$colarr[\''.$col.'\'],'.$order.',';
}

$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
    foreach ($arr as $k => $v) {
        $k = substr($k,1);
        if (!isset($ret[$k])) $ret[$k] = $array[$k];
        $ret[$k][$col] = $array[$k][$col];
    }
}
return $ret;


} 
-1
répondu Chirag Pipariya 2013-12-19 15:19:41
  <?php

$inventory = array(

   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),
   array("type"=>"pork", "price"=>5.43),

);



function myfunc($a,$b){
return strnatcmp($a['price'],$b['price']);
}
$result=usort ($inventory,"myfunc");?>
<pre><?php print_r(array_reverse($inventory)); ?></pre>

la solution la plus simple :)

la sortie est,

Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

    [1] => Array
        (
            [type] => fruit
            [price] => 3.5
        )

    [2] => Array
        (
            [type] => milk
            [price] => 2.9
        )

)
-2
répondu Akhilhh 2014-08-04 05:22:38

essayez ceci:

asort($array_to_sort, SORT_NUMERIC);

pour référence, voir ce: http://php.net/manual/en/function.asort.php

voir divers drapeaux de tri ici: http://www.php.net/manual/en/function.sort.php

-3
répondu sarsnake 2013-12-19 15:17:39