¿Cómo ordenar la matriz multidimensional por valor?

1129

¿Cómo puedo ordenar esta matriz por el valor de la clave "orden"? Aunque los valores son actualmente secuenciales, no siempre lo serán.

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
fuente
la forma más rápida es utilizar el módulo de ordenamiento isomorfo que funciona de forma nativa tanto en el navegador como en el nodo, que admite cualquier tipo de entrada, campos calculados y órdenes de clasificación personalizadas.
Lloyd

Respuestas:

1734

Pruebe usort , si todavía tiene PHP 5.2 o anterior, primero deberá definir una función de clasificación:

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

usort($myArray, 'sortByOrder');

A partir de PHP 5.3, puede usar una función anónima:

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

Y finalmente con PHP 7 puedes usar el operador de nave espacial :

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

Para extender esto a la clasificación multidimensional, haga referencia al segundo / tercer elemento de clasificación si el primero es cero, se explica mejor a continuación. También puede usar esto para ordenar los subelementos.

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 necesita conservar las asociaciones de claves, use uasort(): consulte la comparación de las funciones de ordenación de matrices en el manual

Christian Studer
fuente
2
Mi fraseo está un poco apagado, lo editaré. Lo que quise decir es que si no está en PHP 5.3, debe crear una función especial solo para esta clasificación particular (que de alguna manera no es muy elegante). De lo contrario, podría usar una función anónima allí mismo.
Christian Studer
23
@ Jonathan: Realmente no puedes ver la mayor parte del trabajo que hace PHP. Toma la matriz y comienza con dos elementos, que pasó a esta función definida por el usuario. Su función es responsable de compararlos: si el primer elemento es más grande que el segundo, devuelva un número entero positivo, si es más pequeño, devuelva uno negativo. Si son equel, devuelve 0. PHP luego envía otros dos elementos a su función y continúa haciéndolo, hasta que la matriz se haya ordenado. La función aquí es muy corta, podría ser mucho más complicado si no compararas enteros.
Christian Studer
61
Protip: utilícelo uasort()si desea conservar las claves de la matriz.
thaddeusmt
15
Tenga cuidado si los valores ordenables son números decimales. Si la función de clasificación obtiene $ a = 1 y $ b = 0.1, la diferencia es 0.9, pero la función devuelve un int, en este caso 0, por lo que $ a y $ b se consideran iguales y se ordenan incorrectamente. Es más confiable comparar si $ a es mayor que $ b o igual, y devolver -1, 1 o 0 en consecuencia.
Greenlandi
37
Me tomó un tiempo descubrirlo. Para ordenar el orden inverso (DESC) puede cambiar $ a y $ b. Entonces $ b ['orden'] - $ a ['orden']
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 '.
fuente
77
@ noc2spam Me complace ayudar, pero considere seguir la sugerencia de Studer, que probablemente sea más eficiente y seguramente más ordenada.
o0 '.
1
@Lohoris seguro amigo, también lo estoy revisando. Ayer habría sido un día más duro en la oficina si no hubiera encontrado esta pregunta :-)
Gogol
hmm no puedo agregar una respuesta ... bueno, lo puse aquí porque no necesito esos puntos estúpidos: así que para una ordenación multidimensional es (casi) lo mismo (srry tienes que copiar pegar y reformatearlo): function aasort (& $ array , $ clave1, $ clave2, $ clave3) {$ sorter = array (); $ ret = array (); restablecer ($ array); foreach ($ array como $ ii => $ va) {$ sorter [$ ii] = getPrice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ sorter); foreach ($ clasificador como $ ii => $ va) {$ ret [$ ii] = $ array [$ ii]; } $ array = $ ret; }
Jaxx0rr
3
Mucho más fácil de aplicar que la respuesta anterior
Marcel
1
¡¡USTED ES MARAVILLOSO!! Funciona como encanto para PHP 7.2 MUCHAS GRACIAS QUERIDA :)
Kamlesh
270

Yo uso esta función:

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
fuente
3
Funciona muy bien La solución única que permite agregar una dirección de clasificación. ¡Gracias!
Ivo Pereira
2
Para una alternativa que admita instrucciones de clasificación y muchas características adicionales, puede consultar mi respuesta aquí : también tiene la ventaja de que no se usa array_multisorty, por lo tanto, no es necesario asignar previamente $sort_col, ahorrando tiempo y memoria .
Jon
Funciona muy bien para mí, pero ... ¿por qué es necesario especificar en &$arrlugar de solo $arr?
Radu Murzea
2
@RaduMurzea para que la matriz pase por referencia y pueda ser modificada por la función, en lugar de que la función reciba una copia
Tom Haigh
1
@AdrianP. : el conjunto se pasa por referencia, por lo que modificará el conjunto pasado en lugar de devolver una copia ordenada
Tom Haigh
72

Usualmente uso usort y paso mi propia función de comparación. En este caso, es muy simple:

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

En PHP 7 usando el operador de nave espacial:

usort($array, function($a, $b) {
    return $a['order'] <=> $b['order'];
});
Jan Fabry
fuente
44
Maldición, fui 30 segundos más lento. ¿No es $ a - $ b sin embargo?
Christian Studer
3
Siempre me equivoco. Permítanme pensar en el manual: el valor de retorno debe ser menor que cero si el primer argumento se considera menor que el segundo. Entonces, si $a['order']es 3 y $b['order']es 6, devolveré -3. ¿Correcto?
Jan Fabry
3
Bueno, devuelve b - a, por lo que será 3. Y, por lo tanto, se ordenó incorrectamente.
Christian Studer
26
Ah OKAY. Estaba usando aritmética no lógica, donde la idea en su cabeza no coincide con las palabras que produce. Esto se estudia con mayor frecuencia los viernes por la tarde.
Jan Fabry
en algunos casos, la respuesta anterior es devolver un resultado incorrecto ... referencia stackoverflow.com/questions/50636981/…
Bilal Ahmed
45

Un enfoque para lograr esto sería así

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

Resultado:

    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
fuente
18

Para ordenar la matriz por el valor de la tecla "título" use:

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

strcmp compara las cuerdas.

uasort () mantiene las claves de la matriz tal como fueron definidas.

BK
fuente
strcmp es una ayuda notable para los tipos varchar, me gustó esta respuesta para abreviar y rápido
StudioX
17
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

Esto se encarga de los alfabetos en mayúsculas y minúsculas.

Nitrodbz
fuente
44
¿Cómo responde esto a la pregunta de ordenar por una clave de matriz particular?
Seano
12

Uso array_multisort(),array_map()

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

print_r($array);

MANIFESTACIÓN

Ghanshyam Nakiya
fuente
Tenga en cuenta que este enfoque emitirá un aviso. array_multisorthace referencia a su primer parámetro.
Kami Yang
5

El enfoque más flexible sería utilizar este método.

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

este es el por qué:

  • Puede ordenar por cualquier clave (también anidada como 'key1.key2.key3'o ['k1', 'k2', 'k3'])

  • Funciona tanto en matrices asociativas como no asociativas ( $assocflag)

  • No usa referencia: devuelve una nueva matriz ordenada

En su caso, sería tan simple como:

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

Este método es parte de esta biblioteca .

Minwork
fuente
1

Seamos realistas: php NO tiene una función simple para manejar adecuadamente cada escenario de ordenación de matriz.

Esta rutina es intuitiva, lo que significa una depuración y mantenimiento más rápidos:

// 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
fuente
44
"Seamos sinceros: php NO tiene una función simple para manejar adecuadamente cada escenario de ordenación de matriz". Eso es exactamente para lo que usort / ksort / asort están diseñados ^^ '
Ben Cassinat
3
En realidad, PHP tiene muchas funciones de clasificación que se pueden usar para manejar cada escenario de ordenación de matriz.
axiac
Con respecto a la depuración y el mantenimiento, el uso de globales una gran señal de alerta y generalmente se desaconseja . ¿Por qué se mysql_fetch_arraydemuestra esta pregunta en lugar de la matriz fuente del OP, y que no hay una explicación de lo que está haciendo su código y cuál puede esperar que sea el resultado? En general, este es un enfoque muy complejo para lograr el resultado final deseado.
fyrye
@tonygil No puedo determinar cuáles son sus resultados esperados a partir de su respuesta y el conjunto de datos del OP. Puede ser obvio para usted, pero no sé cómo su respuesta responde a la pregunta del OP. Sin embargo, puede pasar por referencia en lugar de usar globalver: 3v4l.org/FEeFC Esto produce una variable definida explícitamente, en lugar de una que se puede cambiar y acceder globalmente.
fyrye
0

También puede ordenar la matriz multidimensional para múltiples valores como

$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"
    ],

];

con

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

Salida usando 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) usar strcmp sería una buena opción para comparar las cadenas.

StudioX
fuente