Come ordinare una matrice multidimensionale per valore?


1129

Come posso ordinare questo array in base al valore della chiave "ordine"? Anche se i valori sono attualmente sequenziali, non lo saranno sempre.

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


il modo più rapido è utilizzare il modulo di ordinamento-array isomorfo che funziona nativamente sia nel browser che nel nodo, supportando qualsiasi tipo di input, campi calcolati e ordinamenti personalizzati.
Lloyd,

Risposte:


1734

Prova un usort , se sei ancora su PHP 5.2 o precedente, dovrai prima definire una funzione di ordinamento:

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

usort($myArray, 'sortByOrder');

A partire da PHP 5.3, puoi usare una funzione anonima:

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

E infine con PHP 7 puoi usare l' operatore di astronave :

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

Per estenderlo allo smistamento multidimensionale, fai riferimento al secondo / terzo elemento di ordinamento se il primo è zero, meglio spiegato di seguito. Puoi anche usarlo per l'ordinamento su elementi secondari.

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

Se è necessario conservare le associazioni di tasti, utilizzare uasort()- vedere il confronto delle funzioni di ordinamento degli array nel manuale


2
Il mio fraseggio è un po 'fuori, lo modificherò. Quello che volevo dire è che se non sei su PHP 5.3, devi creare una funzione speciale solo per questo particolare ordinamento (che in qualche modo non è molto elegante). Altrimenti potresti usare una funzione anonima proprio lì.
Christian Studer,

23
@Jonathan: Non riesci davvero a vedere gran parte del lavoro svolto da PHP. Prende l'array e inizia con due elementi, che è passato a questa funzione definita dall'utente. La tua funzione è quindi responsabile di confrontarli: se il primo elemento è più grande del secondo, restituisce un numero intero positivo, se è più piccolo, restituisce uno intero negativo. Se sono equel, restituisci 0. PHP quindi invia altri due elementi alla tua funzione e continua a farlo, fino a quando l'array non è stato ordinato. La funzione qui è molto breve, potrebbe essere molto più complicata se non si confrontassero numeri interi.
Christian Studer,

61
Protip: utilizzare uasort()se si desidera conservare le chiavi dell'array.
thaddeusmt

15
Fare attenzione se i valori ordinabili sono numeri decimali. Se la funzione di ordinamento ottiene $ a = 1 e $ b = 0,1, la differenza è 0,9, ma la funzione restituisce un int, in questo caso 0, quindi $ a e $ b sono considerati uguali e ordinati in modo errato. È più affidabile confrontare se $ a è maggiore di $ b o uguale e restituisce -1, 1 o 0 di conseguenza.
Groenlandia,

37
Mi ci è voluto un po 'per scoprirlo. Per ordinare l'ordine inverso (DESC) è possibile cambiare $ ae $ b. Quindi $ b ['order'] - $ a ['order']
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");

7
@ noc2spam Sono lieto di aiutarti, ma considera di seguire il suggerimento degli studiosi che è probabilmente più efficiente e sicuramente più ordinato!
o0 '.

1
@Lohoris, amico, lo sto provando anch'io. Ieri sarebbe stata una giornata più dura in ufficio se non avessi trovato questa domanda :-)
Gogol

hmm non posso aggiungere una risposta .. bene l'ho messo qui perché non ho bisogno di quegli stupidi punti: quindi per un ordinamento multidimensionale è (quasi) la stessa cosa (srry devi copiare e riformattare): funzione aasort (& $ array , $ chiave1, $ chiave2, $ chiave3) {$ sorter = array (); $ ret = array (); reset ($ array); foreach ($ array as $ ii => $ va) {$ sorter [$ ii] = getPrice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ sorter); foreach ($ sorter come $ ii => $ va) {$ ret [$ ii] = $ array [$ ii]; } $ array = $ ret; }
Jaxx0rr

3
Molto più facile da applicare della risposta di cui sopra
Marcel

1
SEI FANTASTICO!! FUNZIONA COME IL FASCINO PER PHP 7.2 GRAZIE MOLTO CARO :)
Kamlesh,

270

Uso questa funzione:

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

3
Funziona molto bene La soluzione unica in grado di aggiungere una direzione di ordinamento. Grazie!
Ivo Pereira,

2
Per un'alternativa che supporta le indicazioni per l'ordinamento e molte altre funzioni, potresti dare un'occhiata alla mia risposta qui - ha anche il vantaggio che non usa array_multisorte quindi non ha bisogno di preallocare $sort_col, risparmiando tempo e memoria .
Jon,

Funziona benissimo per me, ma ... perché è necessario specificare &$arranziché solo $arr?
Radu Murzea,

2
@RaduMurzea, quindi l'array viene passato per riferimento e può essere modificato dalla funzione, anziché dalla funzione che riceve una copia
Tom Haigh

1
@AdrianP. : l'array viene passato per riferimento, quindi modificherà l'array passato anziché restituire una copia ordinata
Tom Haigh

72

Di solito uso Usort e passo la mia funzione di confronto. In questo caso, è molto semplice:

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

In PHP 7 usando l'operatore dell'astronave:

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

4
Accidenti, ero più lento di 30 secondi. Non è $ a - $ b però?
Christian Studer,

3
Ho sempre sbagliato. Fammi pensare dal manuale: il valore di ritorno deve essere inferiore a zero se il primo argomento è considerato inferiore al secondo. Quindi se $a['order']è 3 ed $b['order']è 6, restituirò -3. Corretta?
Jan Fabry,

3
Bene, tu restituisci b - a, quindi sarà 3. E quindi ordinato in modo errato.
Christian Studer,

26
Ah. OK. Stavo usando l'aritmetica non logica, in cui l'idea nella tua testa non corrisponde alle parole che produci. Questo è studiato più frequentemente il venerdì pomeriggio.
Jan Fabry,

in alcuni casi sopra la risposta è restituire un risultato errato .. riferimento stackoverflow.com/questions/50636981/…
Bilal Ahmed

45

Un approccio per raggiungere questo obiettivo sarebbe così

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

Risultato:

    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
            )

    )

18

Per ordinare l'array in base al valore della chiave "title", utilizzare:

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

strcmp confronta le stringhe.

uasort () mantiene le chiavi dell'array così come sono state definite.


strcmp è un aiuto notevole per i tipi di varchar, mi è piaciuta questa risposta in breve e veloce
StudioX

17
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

Questo si occupa di alfabeti sia maiuscoli che minuscoli.


4
In che modo questo risponde alla domanda di ordinamento per una particolare chiave dell'array?
Seano,

12

Usa array_multisort(),array_map()

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

print_r($array);

DEMO


Si noti che questo approccio emetterà un avviso. array_multisortfa riferimento al suo primo parametro.
Kami Yang,

5

L'approccio più flessibile sarebbe utilizzare questo metodo

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

Ecco perché:

  • Puoi ordinare per qualsiasi tasto (anche nidificato come 'key1.key2.key3'o ['k1', 'k2', 'k3'])

  • Funziona sia su array associativi che non associativi ( $assocflag)

  • Non usa riferimento - restituisce un nuovo array ordinato

Nel tuo caso sarebbe semplice come:

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

Questo metodo fa parte di questa libreria .


1

Ammettiamolo: php NON ha una semplice funzione pronta all'uso per gestire correttamente ogni scenario di ordinamento di array.

Questa routine è intuitiva, il che significa debug e manutenzione più rapidi:

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

4
"Ammettiamolo: php NON ha una semplice funzione pronta all'uso per gestire correttamente ogni scenario di ordinamento di array." Questo è esattamente ciò per cui sono stati progettati usort / ksort / asort ^^ '
Ben Cassinat,

3
In realtà PHP ha molte funzioni di ordinamento che possono essere utilizzate per gestire ogni scenario di ordinamento di array.
axiac,

Per quanto riguarda il debug e la manutenzione, l'uso di globalè un'enorme bandiera rossa ed è generalmente scoraggiato . Perché viene mysql_fetch_arraydimostrato per questa domanda invece dell'array di origine dell'OP, e che non vi è alcuna spiegazione di ciò che il codice sta facendo e di cosa ci si può aspettare dal risultato? Nel complesso, questo è un approccio molto complesso per raggiungere il risultato finale desiderato.
fyrye,

@tonygil Non sono in grado di determinare quali risultati attesi derivano dalla tua risposta e dal set di dati del PO. Potrebbe essere ovvio per te, ma non so come la tua risposta risponda alla domanda del PO. Tuttavia, puoi passare per riferimento invece di usare globalsee: 3v4l.org/FEeFC Questo produce una variabile esplicitamente definita, piuttosto che una che può essere modificata e accessibile a livello globale.
Fyrye,

0

È inoltre possibile ordinare un array multidimensionale per più valori come as

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

Uscita 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) usare strcmp sarebbe una buona opzione per confrontare le stringhe.

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.