Ordina array PHP per valore di sottoarray


110

Ho la seguente struttura ad array:

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

Qual è il modo migliore per ordinare l'array in modo incrementale, in base a optionNumber?

Quindi i risultati assomigliano a:

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

Risposte:


204

Usa usort.

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

...

usort($array, "cmp_by_optionNumber");

In PHP ≥5.3, dovresti invece usare una funzione anonima :

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

Si noti che entrambi i codici sopra assumono che $a['optionNumber']sia un numero intero. Usa @St. La soluzione di John Johnson se sono stringhe.


In PHP ≥7.0, usa l' operatore astronave<=> invece della sottrazione per evitare problemi di overflow / troncamento.

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

1
Questo non mi aiuta molto perché usort richiede che gli fornisca una funzione da usare - che è la parte difficile che non riesco a capire
Sjwdavies

17
Beh, ti ha appena dato la funzione da usare. E dovrai accettare che non c'è sempre una funzione incorporata per fare quello che vuoi, devi scriverla tu stesso. Le funzioni di confronto richiedono solo un ritorno di 1, 0 o -1 che indica l'ordinamento per due elementi.
Tesserex

1
Ho approfondito Usort e in realtà è piuttosto interessante. Ho scritto una semplice funzione di confronto con quella sopra, ma ho perso il '=='. Grazie per l'aiuto ragazzi
Sjwdavies

3
Ora anche come chiusura: - usort ($ array, function ($ a, $ b) {return $ b ["optionNumber"] - $ a ["optionNumber"];});
Joeri

1
@ KiloumapL'artélon Se il risultato è < 0, indica la funzione di ordinamento che adovrebbe apparire prima b. Se è > 0allora bdovrebbe comparire davanti a.
kennytm

57

Uso usort

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

7
@ BenSinclair, questo perché la soluzione di Kenny è per i numeri, questa soluzione è per le stringhe. Sono entrambi corretti :-) +1 per questa alternativa.
kubilay

Per l'ordinamento senza distinzione tra maiuscole e minuscole, utilizzare strcasecmp invece di strcmp
user570605

possiamo definire la chiave per il secondo ordine in array significa che eseguiamo prima l'ordinamento con optionNumber quindi l'ordinamento con lastUpdated. Come puoi fare questa cosa?
Bhavin Thummar

16

Ho usato entrambe le soluzioni di KennyTM e AJ Quick e ho creato una funzione che può aiutare in questo problema per molti casi come l' uso dell'ordinamento ASC o DESC o della conservazione delle chiavi o se si hanno oggetti come figli dell'array .

Ecco questa funzione (funziona per PHP7 e versioni successive a causa dell'operatore di astronave):

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

modificare

La prima parte può essere riscritta usando uasort()e la funzione sarà più breve (funziona per PHP7 e superiori a causa dell'operatore di astronave):

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

Questa è la migliore risposta più utile qui, dovrebbe essere in cima;)
Edi Budimilic

@EdiBudimilic grazie, lo apprezzo! A proposito, ho aggiornato la mia risposta e ho aggiunto una versione più breve di questa funzione :)
Pigalev Pavel

1
Per far funzionare questo per me, ho dovuto usare >(maggiore di) invece di -(meno) durante il confronto $ae i $bvalori poiché stavo confrontando le stringhe. Funziona ancora comunque.
James

1
@ James hai ragione. Ho cambiato la risposta e aggiunto l'uso dell'operatore di astronave (<=>). Ora dovrebbe funzionare bene.
Pigalev Pavel

C'è un modo per rendere questo caso insensibile?
loeffel

4

I tasti vengono rimossi quando si utilizza una funzione come quelle sopra. Se i tasti sono importanti, la seguente funzione la manterrebbe ... ma i cicli foreach sono piuttosto inefficienti.

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

Usa arsort invece di asort se vuoi dall'alto verso il basso.

Credito codice: http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/


4

Utilizzando array_multisort (), array_map ()

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

print_r($array);

DEMO


2
Funziona molto facilmente. Grazie. Tutto quello che dovevo fare era cambiare il nome della mia colonna e ha funzionato.
Kobus Myburgh

2
Ciò preserva anche le chiavi per l'array padre
JonnyS

3

PHP 5.3+

usort($array, function($a,$b){ return $a['optionNumber']-$b['optionNumber'];} );
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.