Jak posortować tablicę wielowymiarową według wartości?

1129

Jak mogę posortować tę tablicę według wartości klucza „zamówienie”? Mimo że wartości są obecnie sekwencyjne, nie zawsze będą.

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
        )
)
stef
źródło
najszybszym sposobem jest użycie izomorficznego modułu macierzy sortowania , który działa natywnie zarówno w przeglądarce, jak i w węźle, obsługując dowolny typ danych wejściowych, pól obliczeniowych i niestandardowe porządki sortowania.
Lloyd

Odpowiedzi:

1732

Spróbuj usort , jeśli nadal korzystasz z PHP 5.2 lub wcześniejszego, musisz najpierw zdefiniować funkcję sortowania:

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

usort($myArray, 'sortByOrder');

Począwszy od PHP 5.3, możesz użyć anonimowej funkcji:

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

Wreszcie w PHP 7 możesz użyć operatora statku kosmicznego :

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

Aby rozszerzyć to na sortowanie wielowymiarowe, odwołaj się do drugiego / trzeciego elementu sortującego, jeśli pierwszy ma wartość zero - najlepiej wyjaśnij poniżej. Możesz także użyć tego do sortowania podelementów.

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

Jeśli chcesz zachować kluczowe powiązania, użyj uasort()- patrz porównanie funkcji sortowania tablic w instrukcji

Christian Studer
źródło
2
Moje frazowanie jest trochę wyłączone, zredaguję to. Chodziło mi o to, że jeśli nie korzystasz z PHP 5.3, musisz utworzyć specjalną funkcję tylko dla tego konkretnego sortowania (co w jakiś sposób nie jest zbyt eleganckie). W przeciwnym razie możesz użyć anonimowej funkcji właśnie tam.
Christian Studer
23
@Jonathan: Naprawdę nie widać większości pracy wykonywanej przez PHP. Pobiera tablicę i zaczyna od dwóch elementów, które przekazał do tej funkcji zdefiniowanej przez użytkownika. Twoja funkcja jest następnie odpowiedzialna za ich porównanie: Jeśli pierwszy element jest większy od drugiego, zwróć dodatnią liczbę całkowitą, jeśli jest mniejsza, zwróć ujemną. Jeśli są równe, zwróć 0. PHP następnie wysyła dwa inne elementy do twojej funkcji i kontynuuje to, dopóki tablica nie zostanie posortowana. Funkcja jest tutaj bardzo krótka, może być znacznie bardziej skomplikowana, jeśli nie będziesz porównywać liczb całkowitych.
Christian Studer
61
Protip: użyj, uasort()jeśli chcesz zachować klucze tablicy.
thaddeusmt
15
Zachowaj ostrożność, jeśli sortowalne wartości są liczbami dziesiętnymi. Jeśli funkcja sortująca dostaje $ a = 1 i $ b = 0,1, różnica wynosi 0,9, ale funkcja zwraca int, w tym przypadku 0, więc $ a i $ b są uważane za równe i niepoprawnie posortowane. Bardziej wiarygodne jest porównywanie, jeśli $ a jest większe niż $ b lub równe, i zwraca odpowiednio -1, 1 lub 0.
Greenlandi
37
Zajęło mi to trochę czasu, aby się dowiedzieć. Aby posortować odwrotną kolejność (DESC), możesz przełączyć $ a i $ b. Więc $ b ['zamówienie'] - $ a ['zamówienie']
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");
o0 ”.
źródło
7
@ noc2spam Cieszę się, że mogę pomóc, ale rozważ skorzystanie z sugestii studenta, która jest prawdopodobnie bardziej wydajna i na pewno bardziej schludna!
o0 ”.
1
@Lohoris na pewno stary, ja też to sprawdzam. Wczoraj byłby trudniejszy dzień w biurze, gdybym nie znalazł tego pytania :-)
Gogol
hmm nie mogę dodać odpowiedzi .. cóż, umieściłem to tutaj, bo nie potrzebuję tych głupich punktów: więc dla wielowymiarowego sortowania jest to (prawie) to samo (srry, musisz skopiować i ponownie sformatować): function aasort (& $ array , $ key1, $ key2, $ key3) {$ sorter = array (); $ ret = array (); reset (tablica $); foreach ($ array as $ ii => $ va) {$ sorter [$ ii] = getPrice ($ va [$ key1] [$ key2] [$ key3]); } arsort ($ sorter); foreach ($ sorter as $ ii => $ va) {$ ret [$ ii] = $ array [$ ii]; } $ array = $ ret; }
Jaxx0rr
3
O wiele łatwiej jest aplikować niż powyższa odpowiedź
Marcel
1
JESTEŚ NIESAMOWITY!! DZIAŁA JAK CHARM DLA PHP 7.2 DZIĘKI DUŻO
SZANOWI
270

Korzystam z tej funkcji:

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');
Tom Haigh
źródło
3
Działa bardzo dobrze Unikalne rozwiązanie umożliwiające dodanie kierunku sortowania. Dzięki!
Ivo Pereira,
2
Dla alternatywy, która obsługuje wskazówki sortowania i wiele dodatkowych funkcji, możesz rzucić okiem na moją odpowiedź tutaj - ma również tę zaletę, że nie używa, array_multisorta zatem nie wymaga wstępnej alokacji $sort_col, oszczędzając czas i pamięć .
Jon
Działa świetnie dla mnie, ale ... dlaczego konieczne jest określenie &$arrzamiast po prostu $arr?
Radu Murzea,
2
@RaduMurzea więc tablicy są przekazywane przez odniesienie i może być modyfikowana przez funkcję, zamiast funkcji otrzymanie kopii
Tom Haigh
1
@AdrianP. : tablica jest przekazywana przez odniesienie, więc zmodyfikuje przekazaną tablicę, zamiast zwracać posortowaną kopię
Tom Haigh
72

Zwykle używam usort i przekazuję własną funkcję porównywania. W tym przypadku jest to bardzo proste:

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

W PHP 7 za pomocą operatora statku kosmicznego:

usort($array, function($a, $b) {
    return $a['order'] <=> $b['order'];
});
Jan Fabry
źródło
4
Cholera, byłem 30 sekund wolniejszy. Czy to nie jest $ a - $ b?
Christian Studer
3
Zawsze źle to rozumiem. Niech pomyślę z instrukcji: zwracana wartość musi być mniejsza niż zero, jeśli pierwszy argument jest uważany za mniejszy niż drugi. Więc jeśli $a['order']jest 3, a $b['order']ma 6, zwrócę -3. Poprawny?
Jan Fabry
3
Cóż, zwracasz b - a, więc będzie to 3. I w ten sposób niepoprawnie posortowane.
Christian Studer
26
Ach OK. Użyłem nielogicznej arytmetyki, w której pomysł w twojej głowie nie pasuje do twoich słów. Jest to badane najczęściej w piątkowe popołudnia.
Jan Fabry,
w niektórych przypadkach powyższa odpowiedź to zwrócenie błędnego wyniku .. odniesienie stackoverflow.com/questions/50636981/...
Bilal Ahmed
45

Jedno podejście do osiągnięcia tego byłoby takie

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

Wynik:

    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
            )

    )
ajuchacko91
źródło
18

Aby posortować tablicę według wartości klucza „tytuł”:

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

strcmp porównaj ciągi.

Funkcja uasort () utrzymuje klucze tablicy tak, jak zostały zdefiniowane.

BK
źródło
strcmp jest znaczącą pomocą dla typów varchar, podobało mi się to krótko i szybko
StudioX
17
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

Dotyczy to zarówno wielkich, jak i małych liter.

Nitrodbz
źródło
4
Jak to odpowiada na pytanie dotyczące sortowania według określonego klucza tablicy?
Seano,
12

Użyj array_multisort(),array_map()

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

print_r($array);

PRÓBNY

Ghanshyam Nakiya
źródło
Pamiętaj, że takie podejście spowoduje wysłanie powiadomienia. array_multisortodwołuje się do pierwszego parametru.
Kami Yang,
5

Najbardziej elastycznym podejściem byłoby zastosowanie tej metody

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

dlatego:

  • Możesz sortować według dowolnego klucza (również zagnieżdżonego jak 'key1.key2.key3'lub ['k1', 'k2', 'k3'])

  • Działa zarówno na tablicach asocjacyjnych, jak i nie asocjacyjnych ( $assocflaga)

  • Nie używa referencji - zwraca nową posortowaną tablicę

W twoim przypadku byłoby to tak proste jak:

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

Ta metoda jest częścią tej biblioteki .

Minwork
źródło
1

Spójrzmy prawdzie w oczy: php NIE ma prostej, gotowej do użycia funkcji, aby poprawnie obsługiwać każdy scenariusz sortowania tablic.

Ta procedura jest intuicyjna, co oznacza szybsze debugowanie i konserwację:

// 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);
    }
}
Tony Gil
źródło
4
„Spójrzmy prawdzie w oczy: php NIE ma prostej, gotowej do użycia funkcji, aby poprawnie obsługiwać każdy scenariusz sortowania tablicowego.” Właśnie to zaprojektowano dla usort / ksort / asort dla ^^ '
Ben Cassinat
3
W rzeczywistości PHP ma wiele funkcji sortujących , których można użyć do obsługi każdego scenariusza sortowania tablicowego.
aksjomat
Jeśli chodzi o debugowanie i konserwację, użycie globaljest ogromną czerwoną flagą i ogólnie jest odradzane . Dlaczego mysql_fetch_arrayzademonstrowano to pytanie zamiast tablicy źródłowej OP i że nie ma wyjaśnienia, co robi Twój kod i czego można oczekiwać po wyniku? Ogólnie jest to bardzo złożone podejście do osiągnięcia pożądanego rezultatu końcowego.
fyrye
@tonygil Nie jestem w stanie określić oczekiwanych rezultatów na podstawie odpowiedzi i zestawu danych PO. To może być dla ciebie oczywiste, ale nie wiem, jak twoja odpowiedź odpowiada na pytanie PO. Można jednak podać odniesienie zamiast używać globalsee: 3v4l.org/FEeFC To tworzy wyraźnie zdefiniowaną zmienną, a nie zmienną, która może być zmieniana i dostępna globalnie.
fyrye
0

Możesz także sortować tablicę wielowymiarową pod kątem wielu wartości, takich jak 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"
    ],

];

z

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

Wyjście przy użyciu 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) użycie strcmp byłoby dobrym rozwiązaniem do porównania ciągów.

StudioX
źródło