¿Cómo puedo ordenar matrices y datos en PHP?

292

Esta pregunta pretende ser una referencia para preguntas sobre la ordenación de matrices en PHP. Es fácil pensar que su caso particular es único y merece una nueva pregunta, pero la mayoría son variaciones menores de una de las soluciones en esta página.

Si su pregunta se cierra como un duplicado de esta, solicite que se vuelva a abrir su pregunta solo si puede explicar por qué difiere notablemente de todo lo que se muestra a continuación.

¿Cómo clasifico una matriz en PHP?
¿Cómo clasifico una matriz compleja en PHP?
¿Cómo clasifico una matriz de objetos en PHP?


  1. Matrices unidimensionales básicas; Incl. Matrices multidimensionales, incl. matrices de objetos; Incl. Ordenar una matriz basada en otra

  2. Ordenar con SPL

  3. Tipo estable

Para la respuesta práctica usando las funciones existentes de PHP, ver 1., para la respuesta académica detallada sobre algoritmos de clasificación (qué funciones de PHP implementan y cuáles puede necesitar para casos realmente, muy complejos), consulte 2.

difunto
fuente
@jterry Exactamente, es por eso que hice esto para finalmente tener una buena pregunta de referencia para cerrar. Contestar cada copo de nieve único individualmente no ayuda a nadie. :)
deceze
3
Creo que la gente debería echar un vistazo a php.net
Alexander Jardim
@Alex Ha! Absolutamente. El problema es: nadie RTFM. : D
deceze
2
Ya tenemos esas respuestas, le sugiero que haga una lista de las mejores respuestas dentro de cada respuesta aquí en lugar de duplicar (o reescribir) el contenido. Además, las matrices tienden a verse individualmente, por lo que el trabajo sigue siendo votar en contra de los engañados en cualquier caso.
hakre
1
@deceze: si nadie RTFM, nadie también RTFQA - las preguntas y respuestas existentes :)
hakre

Respuestas:

164

Arreglos unidimensionales básicos

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

Funciones de clasificación aplicables:

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

La diferencia entre estos es simplemente si las asociaciones de valores clave se mantienen (el "a " funciones), si ordena de bajo a alto o inverso (" r"), si clasifica valores o claves (" k") y cómo compara los valores (" nat" vs. normal). Consulte http://php.net/manual/en/array.sorting.php para obtener una descripción general y enlaces a más detalles.

Conjuntos multidimensionales, incluidos conjuntos de objetos

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

Si desea ordenar $arraypor la clave 'foo' de cada entrada, necesita un función de comparación personalizada . Las sortfunciones anteriores y relacionadas funcionan con valores simples que saben cómo comparar y ordenar. PHP no simplemente "sabe" qué hacer con un valor complejo como el array('foo' => 'bar', 'baz' => 42)embargo; así que necesitas contarlo.

Para hacer eso, necesita crear una función de comparación . Esa función toma dos elementos y debe regresar0 si estos elementos se consideran iguales, un valor inferior a0 si el primer valor es menor y un valor mayor que 0si el primer valor es mayor. Eso es todo lo que se necesita:

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

A menudo, querrás usar un función anónima como devolución de llamada. Si desea utilizar un método o método estático, consulte el otras formas de especificar una devolución de llamada en PHP .

Luego usa una de estas funciones:

Una vez más, solo difieren en si mantienen asociaciones clave-valor y clasifican por valores o claves. Lea su documentación para más detalles.

Ejemplo de uso:

usort($array, 'cmp');

usorttomará dos elementos de la matriz y llamará a su cmpfunción con ellos. Entonces cmp()se llamará con $aas array('foo' => 'bar', 'baz' => 42)y $bcomo otro array('foo' => ..., 'baz' => ...). La función luego regresa a usortcuál de los valores era mayor o si eran iguales. usortrepite este proceso pasando valores diferentes para $ay $bhasta que se ordena la matriz. La cmpfunción se llamará muchas veces, al menos tantas veces como haya valores $array, con diferentes combinaciones de valores para $ay $bcada vez.

Para acostumbrarse a esta idea, intente esto:

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

Todo lo que hizo fue definir una forma personalizada de comparar dos elementos, eso es todo lo que necesita. Eso funciona con todo tipo de valores.

Por cierto, esto funciona en cualquier valor, los valores no tienen que ser matrices complejas. Si desea hacer una comparación personalizada, también puede hacerlo en una simple matriz de números.

sort ¡ordena por referencia y no devuelve nada útil!

Tenga en cuenta que la matriz se ordena en su lugar , no necesita asignar el valor de retorno a nada. $array = sort($array)reemplazará la matriz con true, no con una matriz ordenada. Solo sort($array);funciona

Comparaciones numéricas personalizadas

Si desea ordenar por la bazclave, que es numérica, todo lo que necesita hacer es:

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

Gracias a The PoWEr of MATH esto devuelve un valor <0, 0 o> 0 dependiendo de si $aes menor, igual o mayor que $b.

Tenga en cuenta que esto no funcionará bien para los floatvalores, ya que se reducirán a una inty perderán precisión. Utilice explícita -1, 0y1 los valores de retorno en su lugar.

Objetos

Si tiene una matriz de objetos, funciona de la misma manera:

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

Las funciones

Puede hacer cualquier cosa que necesite dentro de una función de comparación, incluidas las funciones de llamada:

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

Instrumentos de cuerda

Un atajo para la primera versión de comparación de cadenas:

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

strcmphace exactamente lo que se espera de cmpaquí, vuelve -1, 0o 1.

Operador de nave espacial

PHP 7 introdujo el operador de nave espacial , que unifica y simplifica igual / menor / mayor que las comparaciones entre tipos:

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

Ordenar por múltiples campos

Si desea ordenar principalmente por foo, pero si fooes igual para dos elementos, ordene por baz:

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

Para aquellos familiares, esto es equivalente a una consulta SQL con ORDER BY foo, baz.
También vea esta versión abreviada muy ordenada y cómo crear una función de comparación de este tipo dinámicamente para un número arbitrario de teclas .

Ordenar en un orden manual, estático

Si desea ordenar los elementos en un "orden manual" como "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);
}

Por todo lo anterior, si está utilizando PHP 5.3 o superior (y realmente debería hacerlo), use funciones anónimas para un código más corto y para evitar tener otra función global flotando:

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

Así de simple puede ser ordenar una compleja matriz multidimensional. Nuevamente, solo piense en términos de enseñar a PHP cómo saber cuál de los dos elementos es "mayor" ; deja que PHP haga la clasificación real.

También para todo lo anterior, para cambiar entre orden ascendente y descendente, simplemente cambie los argumentos $ay $b. P.ej:

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

Ordenar una matriz basada en otra

Y luego está lo peculiar array_multisort, que le permite ordenar una matriz basada en otra:

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

El resultado esperado aquí sería:

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

Use array_multisortpara llegar allí:

array_multisort($array1, $array2);

A partir de PHP 5.5.0, puede usar array_columnpara extraer una columna de una matriz multidimensional y ordenar la matriz en esa columna:

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

A partir de PHP 7.0.0, también puede extraer propiedades de una matriz de objetos.


Si tiene casos más comunes, no dude en editar esta respuesta.

difunto
fuente
La función de comparación numérica no funciona para valores flotantes; Estoy seguro de que sabes lo que quiero decir :)
Ja͢ck
1
Para el orden estático, solicitaría array_flip()hacer uso de una búsqueda de posición más rápida, por ejemplo, en $order[$a['foo']]lugar de array_search($a['foo'], $order).
Ja͢ck
Puede ser una edición un poco grande: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b pero si crees que es una mejora e incluí todo lo esencial, puedo aplicarlo.
Rizier123
@ Rizier123 Ciertamente aplaudo el esfuerzo, es una muy buena crítica; pero preferiría que lo publicaras como respuesta separada, incluso si es muy similar. Su reescritura contiene muchos detalles (pase por referencia, tabla grande, etc.), pero ese detalle distrae de la introducción sin problemas al tema central del funcionamiento de la función de comparación, en mi humilde opinión. Me refiero explícitamente al manual varias veces a propósito, porque allí es donde se deben buscar esos detalles; no es necesario repetirlo aquí y distraerme de la idea central que estoy tratando de transmitir.
deceze
@deceze El principal desafío, ya que es una Q&A de referencia, es mostrar la información lo más compacta y legible posible y facilitar a los usuarios encontrar su función de clasificación. Modifiqué algunas cosas: gist.github.com/Rizier123/24a6248758b53245a63e839d8e08a32b pero todavía tengo que pensarlo, si es útil y valioso publicarlo como respuesta separada, ya que es un contenido muy similar
Rizier123
139

Bueno, la mayoría de los métodos básicos ya están cubiertos por el engaño . Intentaría ver otros tipos de

Ordenar con 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));

Salida

c
b
a

SplMaxHeap

La clase SplMaxHeap proporciona las principales funcionalidades de un montón, manteniendo el máximo en la parte superior.

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

SplMinHeap

La clase SplMinHeap proporciona las principales funcionalidades de un montón, manteniendo el mínimo en la parte superior.

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

Otros tipos de ordenación

Ordenamiento de burbuja

Del artículo de Wikipedia sobre Bubble Sort:

La clasificación de burbujas, a veces denominada incorrectamente clasificación de hundimiento, es un algoritmo de clasificación simple que funciona recorriendo repetidamente la lista para clasificar, comparando cada par de elementos adyacentes y cambiándolos si están en el orden incorrecto. El paso por la lista se repite hasta que no se necesitan intercambios, lo que indica que la lista está ordenada. El algoritmo recibe su nombre de la forma en que los elementos más pequeños "burbujean" al principio de la lista. Debido a que solo usa comparaciones para operar en elementos, es un tipo de comparación. Aunque el algoritmo es simple, la mayoría de los otros algoritmos de clasificación son más eficientes para listas grandes.

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

Tipo de selección

Del artículo de Wikipedia sobre el tipo de selección:

En informática, la selección por selección es un algoritmo de clasificación, específicamente una clasificación de comparación in situ. Tiene una complejidad de tiempo O (n2), lo que lo hace ineficiente en listas grandes, y generalmente funciona peor que el tipo de inserción similar. La selección de selección destaca por su simplicidad, y tiene ventajas de rendimiento sobre algoritmos más complicados en ciertas situaciones, particularmente donde la memoria auxiliar es limitada.

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

Tipo de inserción

Del artículo de Wikipedia sobre el tipo de inserción:

La ordenación por inserción es un algoritmo de ordenación simple que crea la matriz ordenada final (o lista) un elemento a la vez. Es mucho menos eficiente en listas grandes que los algoritmos más avanzados, como el ordenamiento rápido, el ordenamiento dinámico o la ordenación por fusión. Sin embargo, la ordenación por inserción ofrece varias ventajas:

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

Del artículo de Wikipedia sobre Shellsort:

Shellsort, también conocido como clasificación de Shell o método de Shell, es una clasificación de comparación in situ. Generaliza un tipo de intercambio, como la inserción o el tipo de burbuja, al comenzar la comparación e intercambio de elementos con elementos que están muy separados antes de terminar con elementos vecinos.

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

Tipo de peine

Del artículo de Wikipedia sobre el tipo de peine:

La clasificación por peine es un algoritmo de clasificación relativamente simple diseñado originalmente por Wlodzimierz Dobosiewicz en 1980. Más tarde fue redescubierto por Stephen Lacey y Richard Box en 1991. La clasificación por peine mejora en la clasificación por burbujas.

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

Ordenar fusión

Del artículo de Wikipedia sobre Merge sort:

En ciencias de la computación, un tipo de combinación (también comúnmente deletreado mergesort) es un algoritmo de clasificación basado en comparación O (n log n). La mayoría de las implementaciones producen una ordenación estable, lo que significa que la implementación conserva el orden de entrada de elementos iguales en la salida ordenada

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

Ordenación rápida

Del artículo de Wikipedia sobre Quicksort:

Quicksort, o clasificación de intercambio de partición, es un algoritmo de clasificación desarrollado por Tony Hoare que, en promedio, realiza comparaciones de O (n log n) para ordenar n elementos. En el peor de los casos, hace comparaciones de O (n2), aunque este comportamiento es raro.

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

Tipo de permutación

Del artículo de Wikipedia sobre el tipo de permutación:

Ordenación de permutación, que procede generando las posibles permutaciones de la matriz / lista de entrada hasta descubrir la ordenada.

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

Tipo Radix

Del artículo de Wikipedia sobre el tipo Radix:

En informática, la clasificación por radix es un algoritmo de clasificación de enteros no comparativo que clasifica los datos con claves enteras al agrupar las claves por los dígitos individuales que comparten la misma posición y valor significativos.

// 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
fuente
44
@deceze cubriste todos los conceptos básicos ... tuve que buscar otra forma de ser relevante :)
Baba
55
No veo nada malo con los métodos de clasificación más académicos :) mucho menos útiles para la mayoría de las aplicaciones, pero ocasionalmente se les puede pedir / requerir es útil para tener una referencia, especialmente porque me olvidé de la mayoría de estos con el tiempo
Dave
En realidad, para una ordenación rápida, se recomienda seleccionar pivote como una mediana de tres valores: elementos primero, medio y último . Este es mi ejemplo para la selección de pivote. Eso permite evitar la matriz ordenada inversa en el peor de los casos (lo que provoca O(n^2)comparaciones si usamos solo el primer elemento como pivote)
Alma Do
He oído que spl funciona más rápido que la ordenación de matriz normal. ¿Es correcto?
jewelhuq
Estoy de acuerdo con Dave, hoy en día, casi todos han incluido eso por lo que rara vez lo recuerdo o lo uso.
Mike Nguyen
43

Tipo estable

Digamos que tiene una matriz como esta:

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

Y ahora quieres ordenar solo en la primera letra:

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

El resultado es este:

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

¡El tipo no era estable!

El observador entusiasta puede haber notado que el algoritmo de clasificación de matriz (QuickSort) no produjo un resultado estable y que el orden original entre las palabras de la misma primera letra no se conservó. Este caso es trivial y deberíamos haber comparado toda la cadena, pero supongamos que su caso de uso es más complicado, como dos tipos consecutivos en diferentes campos que no deberían cancelar el trabajo del otro.

La transformación de Schwartz

La transformación de Schwartz , también conocida como modismo decorar-ordenar-decorar, produce un ordenamiento estable con un algoritmo de ordenamiento inherentemente inestable.

Primero, decora cada elemento de matriz con otra matriz que comprende una clave primaria (el valor) y una clave secundaria (su índice o posición):

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

Esto transforma la matriz en esto:

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

Ahora, ajustamos el paso de comparación; volvemos a comparar la primera letra, pero si son iguales, la clave secundaria se utiliza para conservar el orden original:

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

Luego, decoramos:

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

El resultado final:

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

¿Qué pasa con la reutilización?

Debía reescribir su función de comparación para trabajar con los elementos de la matriz transformada; es posible que no desee editar sus delicadas funciones de comparación, así que aquí hay un contenedor para la función de comparación:

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

Escribamos el paso de clasificación usando esta función:

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

Voila! Su código de comparación impecable está de vuelta.

Jack
fuente
Su frase "efectúa un ordenamiento estable con un algoritmo de ordenamiento inherentemente inestable" fue el momento de ah-ha para mí. La página de wikipedia no menciona la palabra estable, que me parece la belleza de la transformación. Vergüenza.
Tyler Collier
1
@TylerCollier Sí, necesitas leer entre líneas la referencia de Wikipedia ... Te ahorré la molestia de hacer eso ;-)
Ja͢ck
15

A partir de PHP 5.3 con cierres, también es posible usar un cierre para determinar el orden de su clasificación.

Por ejemplo, suponiendo que $ array es una matriz de objetos que contienen una propiedad de mes.

 $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);
 }); 
Píldora de naranja
fuente
Solo recuerde que esto eliminará cualquier orden relativo anterior (por ejemplo, el primer objeto "Julio" en la lista ordenada previamente puede terminar al final del grupo de objetos Julio después de la clasificación). Consulte "Clasificación estable" más arriba.
George Langley
9

LINQ

En .NET, LINQ se usa con frecuencia para ordenar, lo que proporciona una sintaxis mucho mejor que las funciones de comparación, especialmente cuando los objetos necesitan ser ordenados por múltiples campos. Hay varios puertos de LINQ to PHP, incluida la biblioteca YaLinqo *. Con él, las matrices se pueden ordenar con una sola línea sin escribir funciones de comparación complejas.

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

Las comparaciones se pueden personalizar aún más al pasar una devolución de llamada como un segundo argumento, por ejemplo:

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

Aquí, '$v->count'es una forma abreviada de function ($v) { return $v->count; }(cualquiera puede ser usado). Estas cadenas de métodos devuelven iteradores, los iteradores se pueden transformar en matrices agregando ->toArray()al final si es necesario.

Internamente, orderByy métodos relacionados con la llamada funciones de clasificación de matriz adecuados ( uasort, krsort, multisort, usortetc.).

LINQ contiene muchos más métodos inspirados en SQL: filtrado, agrupación, unión, agregación, etc. Es el más adecuado para los casos en que se deben realizar transformaciones complejas en matrices y objetos sin depender de bases de datos.

* desarrollado por mí, vea el archivo Léame para más detalles y comparación con otros puertos LINQ

Athari
fuente
3

Clasificación multidimensional por valor clave

Tipo natural de una matriz multidimensional por un valor clave y también mantener el orden original (no mezclar las teclas 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;
}

Caso de prueba:

$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
fuente
2

Es muy conveniente ordenar matrices con función ordenada de Nspl :

Clasificación básica

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

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

Ordenar por resultado de función

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

Ordenar una matriz multidimensional

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

Ordenar una matriz de objetos

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

Ordenar con una función de comparación

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

Puedes ver todos estos ejemplos aquí .

Ihor Burlachenko
fuente
2

Si desea ordenar por el valor clave, puede hacerlo una línea, elegante y clara. Esto ordenará por el precio ascendente. Utiliza array_multisort y 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);

para producir

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

Esta página es muy completa, pero quiero agregar un poco más sobre la increíble utilidad del operador de la nave espacial (operador de comparación de tres vías), un hermoso hijo de PHP7 +.

Usando el operador de la nave espacial para implementar múltiples condiciones de clasificación

Esto da grandes pasos para reducir la hinchazón de código y mejorar la legibilidad.

Al escribir su función de clasificación personalizada ( usort()/ uasort()/ uksort()) para procesar múltiples condiciones, solo necesita escribir matrices balanceadas a cada lado del operador y devolver el resultado. No más bloques de condiciones anidadas o retornos múltiples.

Los elementos de ambos lados del operador se desplazarán de izquierda a derecha, uno a la vez, y se devolverá la evaluación tan pronto como se encuentre un empate o cuando se hayan comparado todos los elementos.

Datos de muestra para mis demostraciones:

$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' => ''
    ]
];

Demostraciones (para evitar la hinchazón de página de Stackoverflow, consulte el enlace de demostración para las salidas):

  • Lógica de clasificación:

    1. DESC booleano (falso = 0, verdadero = 1, entonces verdadero antes de falso)
    2. flotador ASC

      uasort($multidimArray, function($a, $b) {
          return [$b['boolean'], $a['float']] <=> [$a['boolean'], $b['float']];
      });
  • Lógica de clasificación:

    1. ASC mixto
    2. objeto ASC
    3. ASC booleana

      uasort($multidimArray, function($a, $b) {
          return [$a['mixed'], $a['object']->prop, $a['boolean']] <=> [$b['mixed'], $b['object']->prop, $b['boolean']];
      });
  • Lógica de clasificación:

    1. recuento de propiedades del objeto ASC
    2. iterabilidad de DESC mixto
    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']];
      });

Esta sintaxis le permite ordenar valores, resultados funcionales, datos anidados profundamente y ordenar la dirección de una manera elegante. Definitivamente vale la pena ponerlo en su cinturón de herramientas de php ... para casos en los que está procesando datos que no son de base de datos, porque, por supuesto, SQL sería una técnica mucho más sensata.

A su discreción, desde PHP7.4 puede usar la sintaxis de flecha con estas funciones anónimas. El mismo guión con sintaxis de flecha .

mickmackusa
fuente
0

Si alguien quiere una solución más simple para manipular matrices, simplemente use el paquete Laravel Collection, que tiene una función sortBy implementada que le permite ordenar por teclas simplemente.

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

es decir, para ordenar primero por a, luego b, luego c, la cláusula correcta sería

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

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

Rizerzero
fuente
-1

Hay varias formas de ordenar una matriz. Mencionaré algunos métodos para hacer esa tarea. En primer lugar, daré una matriz entera que se llama como '$ números'.

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

Esta es la forma normal de crear una matriz. Supongamos que quiero ordenar esa matriz en orden ascendente. Para eso, se puede usar el método 'sort ()'.

<?php

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

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

Ahora considere la salida de eso,

ingrese la descripción de la imagen aquí

Puede ver que la matriz de números impresos está ordenada. Si desea que esa matriz de números se ordene en orden descendente, puede usar el método 'rsort ()' para esa tarea.

<?php

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

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

considere la salida ..

ingrese la descripción de la imagen aquí

Ahora la matriz está ordenada en orden descendente. Bien, consideremos una matriz asociativa. Daré una matriz asociativa (matriz asociativa significa que, una matriz cuyo índice tiene un valor clave único) como este,

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

Entonces, ahora quiero ordenar esta matriz en orden ascendente según su valor. El método'asort () 'se puede usar para eso.

<?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 ordena el orden descendente según su valor, se puede usar el método 'arsort ()'. Suponga que desea ordenar esa matriz según su valor clave. En esto, se puede usar el método 'ksort ()'.

<?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."  ";
     }
?>

Ahora considere la salida. ingrese la descripción de la imagen aquí

Ahora la matriz se ordena según su valor clave. Si desea ordenar la matriz en orden descendente según su valor clave, se puede utilizar el método 'krsort ()'.

<?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."  ";
    }
?>

Ahora la matriz asociativa se ordena en orden descendente según su valor clave. Mire la salida. ingrese la descripción de la imagen aquí

Estos son algunos de los métodos para ordenar una matriz en orden ascendente o descendente en php. Espero que puedas tener una idea. ¡Gracias!

GT_hash
fuente
Deceze ya no cubre estos puntos de vista con: "La diferencia entre ellos es simplemente si las asociaciones de clave-valor se mantienen (las funciones" a "), si se clasifica de bajo a alto o inverso (" r "), si ordena los valores o las claves ("k") y cómo compara los valores ("nat" frente a lo normal) ". en la respuesta aceptada?
mickmackusa
-2

Lo más simple es usar la función usort para ordenar la matriz sin ningún bucle: a continuación se muestra un ejemplo:

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

Esto se ordenará en orden descendente:

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

Esto se ordenará en orden de finalización:

usort($array_compare, function($a, $b) {
        return ($b['x1'] - $a['x1']) < 0 ? 1 :-1;
    });
pihu
fuente
1
1) El ejemplo y el código son inconsistentes. 2) Esto ya se explica con un detalle insoportable en las respuestas anteriores. 3) ¿Estás tratando de responder a una pregunta diferente?
deceze