Orden personalizado de arrays en PHP
Recientemente me vi en la necesidad de crear una lista de elementos en un orden
muy específico mientras trabajaba con un array en PHP, afortunadamente resulta que
la forma de lograrlo es muy sencilla, gracias a que PHP nos ofrece la función usort
.
A continuación mencionaré como lograr un orden personalizado de arrays en PHP.
El código
Tomando el siguiente ejemplo, explicaré en que consiste:
1<?php2/**3 * Array para ordernar.4 * Asumamos que recibimos este array de un API donde no tenemos control.5 */6$my_array = [7 'DO',8 'FA',9 'LA',10 'MI',11 'RE',12 'SI',13 'SOL',14];1516/**17 * Orden que queremos, donde si tenemos control.18 */19$custom_order = [20 'DO',21 'RE',22 'MI',23 'FA',24 'SOL',25 'LA',26 'SI',27];2829/**30 * Ordenamos el array.31 */32usort(33 $my_array,34 function( $a, $b ) use ( $custom_order ) {35 $a_order = array_search( $a, $custom_order );36 $b_order = array_search( $b, $custom_order );37 if ( false === $a_order ) {38 $a_order = 999;39 }40 if ( false === $b_order ) {41 $b_order = 999;42 }43 return $a_order - $b_order;44 }45);46var_export( $my_array );47
¿Que está pasando?
Lo que la función hace no es muy complejo de digamos, simplemente es un loop que itera sobre cada elemento en el array, y los compara entre si, finalmente asignándoles un valor temporal. La magia aquí sucede al utilizar array_search, que regresa el índice del elemento dentro del array. A menor valor asignado, mayor prioridad se le da en el orden.
1/**2 * Array con indices enfatizados:3 */4$custom_order = [5 [0] => 'DO',6 [1] => 'RE',7 [2] => 'MI',8 [3] => 'FA',9 [4] => 'SOL',10 [5] => 'LA',11 [6] => 'SI',12];13
Por ejemplo, cuando nuestro algoritmo compara DO
vs MI
, está comparando [0]
vs [2]
,
que son los índices de esos elementos en el array:
1if ( false === $a_order ) {2 $a_order = 999;3}4if ( false === $b_order ) {5 $b_order = 999;6}7
Si no encuentra los valores dentro del array (false === $a_order)
les asigna
automaticamente un valor de 999, lo que los colocaría al final de prioridades.
1return $a_order - $b_order;2
Finalmente regresa el resultado de 0 - 2
, o sea -2
, lo que colocaría a DO
por encima de MI
, en el momento en que se compare MI
vs DO
, la operación
sería 2 - 0
, con resultado de 2
lo que mantendría a MI
por debajo de DO
en prioridad.
De esta forma al terminar las comparaciones, tendremos nuestro orden personalizado de arrays en PHP listo.
ACTUALIZACIÓN 27-09-23
Si ya tengo el orden que quiero definido, ¿Por qué necesito ordenar otro array?
Después de mi publicación original, me di cuenta de que no tiene mucho sentido poner como ejemplo un array de un sólo nivel, ya que immediatamente después se está colocando el mismo array pero ordenado, entonces, ¿De qué nos sirve esto?.
La verdadera utilidad viene cuando tenemos que ordenar arrays multidimensionales, de esta forma, en base al valor del array, podemos definir en que lugar lo queremos mostrar, por ejemplo:
1/**2 * Array de equipos recibidos de una API3 */4$teams = [5 [6 'id' => 9384,7 'league' => 'NBA',8 'type' => 'basketball',9 ],10 [11 'id' => 89732,12 'league' => 'MLB',13 'type' => 'baseball',14 ],15 [16 'id' => 52,17 'league' => 'MLS',18 'type' => 'football',19 ],20];21/**22 * Orden por preferencia23 */24$custom_order = [25 'football',26 'basketball',27 'baseball',28];29/**30 * Ordenamos el array.31 */32usort( $teams, ... ); // Misma que usamos anteriormente.33var_export( $teams );34/**35[36 [37 'id' => 52,38 'league' => 'MLS',39 'type' => 'football',40 ],41 [42 'id' => 9384,43 'league' => 'NBA',44 'type' => 'basketball',45 ],46 [47 'id' => 89732,48 'league' => 'MLB',49 'type' => 'baseball',50 ],51];52*/53