PHP Ordenar matriz por valor de subarreglo


110

Tengo la siguiente estructura de matriz:

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

¿Cuál es la mejor manera de ordenar la matriz de forma incremental, según el optionNumber?

Entonces los resultados se ven así:

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

Respuestas:


204

Utilice usort.

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

...

usort($array, "cmp_by_optionNumber");

En PHP ≥5.3, debería usar una función anónima en su lugar:

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

Tenga en cuenta que ambos códigos anteriores asumen que $a['optionNumber']es un número entero. Utilice @St. La solución de John Johnson si son cuerdas.


En PHP ≥7.0, use el operador de nave espacial en<=> lugar de la resta para evitar problemas de desbordamiento / truncamiento.

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

1
Eso realmente no me ayuda, ya que usort requiere que le proporcione una función para usar, que es la parte difícil que no puedo entender
Sjwdavies

17
Bueno, él solo te dio la función para usar. Y tendrás que aceptar que no siempre hay una función incorporada para hacer lo que quieres, tienes que escribirla tú mismo. Las funciones de comparación solo requieren un retorno de 1, 0 o -1 que indica el orden de clasificación de dos elementos.
Tesserex

1
Miré más en usort y en realidad es bastante bueno. Escribí una función de comparación simple con la anterior, sin embargo me perdí el '=='. Gracias por la ayuda chicos
Sjwdavies

3
Ahora también como cierre: - usort ($ array, function ($ a, $ b) {return $ b ["optionNumber"] - $ a ["optionNumber"];});
Joeri

1
@ KiloumapL'artélon Si el resultado es < 0, indica la función de ordenación que adebería aparecer antes b. Si es > 0así, bdebería aparecer antes a.
kennytm

57

Utilizar usort

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

7
@BenSinclair, eso es porque la solución de Kenny es para números, esta solución es para cadenas. Ambos son correctos :-) +1 para esta alternativa.
kubilay

Para una ordenación que no distingue entre mayúsculas y minúsculas, utilice strcasecmp en lugar de strcmp
user570605

¿Podemos definir la clave para el segundo orden en la matriz? significa que primero clasificamos con optionNumber y luego clasificamos con lastUpdated. ¿Cómo se puede hacer esto?
Bhavin Thummar

16

Usé ambas soluciones de Kenny TM y AJ Quick y se me ocurrió una función que puede ayudar en este problema en muchos casos, como usar ASC o DESC para ordenar o preservar claves o si tiene objetos como elementos secundarios de una matriz .

Aquí está esta función (funciona para PHP7 y superior debido al operador de nave espacial):

/**
 * @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;
}

Uso:

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

Editar

La primera parte se puede reescribir usando uasort()y la función será más corta (funciona para PHP7 y superior debido al operador de nave espacial):

/**
 * @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;
}

Esta es la mejor respuesta más útil aquí, debería estar en la parte superior;)
Edi Budimilic

@EdiBudimilic gracias, ¡se lo agradezco! Por cierto, actualicé mi respuesta y agregué una versión más corta de esta función :)
Pigalev Pavel

1
Para que esto funcione para mí, tuve que usar >(mayor que) en lugar de -(menos) al comparar valores $ay $bya que estaba comparando cadenas. Aunque todavía funciona.
James

1
@James, tienes razón. Cambié la respuesta y agregué el uso de operador de nave espacial (<=>). Ahora debería funcionar bien.
Pigalev Pavel

¿Hay alguna manera de hacer que este caso sea insensible?
loeffel

4

Las teclas se eliminan cuando se usa una función como las anteriores. Si las teclas son importantes, la siguiente función las mantendría ... pero los bucles foreach son bastante ineficientes.

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

Use arsort en lugar de asort si quiere de mayor a menor.

Crédito del código: http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/


4

Usando array_multisort (), array_map ()

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

print_r($array);

MANIFESTACIÓN


2
Esto simplemente funciona muy fácilmente. Gracias. Todo lo que tuve que hacer fue cambiar el nombre de mi columna y funcionó.
Kobus Myburgh

2
Esto también conserva las claves para la matriz principal
JonnyS

3

PHP 5.3+

usort($array, function($a,$b){ return $a['optionNumber']-$b['optionNumber'];} );
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.