Sortieren Sie ein flaches, assoziatives Array nach numerischen Werten und dann nach nicht numerischen Schlüsseln

Lesezeit: 8 Minuten

Davids Benutzeravatar
David

Ich habe ein Array von Zeichenfolgenschlüsseln mit numerischen Werten, die zum Erstellen einer Liste von Tags verwendet werden, wobei die Anzahl der Vorkommen jedes Tags dieser ähnelt:

$arrTags = [
    'mango' => 2, 
    'orange' => 4, 
    'apple' => 2,
    'banana' => 3
];

Ich möchte die Tags in einer Liste mit absteigenden Werten anzeigen, um dann die Tag-Namen aufsteigend zu erzeugen:

orange (4)  
banana (3) 
apple (2) 
mango (2)

arsort() ist nicht geeignet, weil es setzen wird mango Vor apple. Ich vermute das usort() mag so sein, aber ich finde kein passendes Beispiel in den Kommentaren auf php.net.

Wie Scott Saunders in seinem Kommentar zu Davids Lösung andeutet, können Sie die Funktionen array_keys() und array_values() verwenden, um die Schleife zu beseitigen. Tatsächlich können Sie dies in einer Codezeile lösen:

array_multisort(array_values($arrTags), SORT_DESC, array_keys($arrTags), SORT_ASC, $arrTags);

  • Danke für diesen Code. Ich habe die genaue Situation als ursprüngliche Frage und das funktioniert für mich. Was mich stört, ist, dass ich nicht genau weiß, was hier passiert. Welche Funktion hat der letzte Parameter? Ich sehe, dass der letzte Parameter (der als Referenz übergeben wird) die einzige Möglichkeit ist, das geänderte Array zurückzugeben, OK. Aber wie hängen die Array-Sets zueinander zusammen? Wenn Multisort seine Arbeit von links nach rechts erledigt, werden die nachfolgenden Arrays mitsortiert. Wenn dies der Fall ist, müssen alle Arrays dieselbe Länge haben, was in der Dokumentation nicht erforderlich ist. #verwirrt

    – andypotter

    18. Februar 2014 um 14:25 Uhr


  • @andypotter: Grundsätzlich array_multi_sort() erstellt intern ein weiteres Array $indirect wobei jeder Index ein Array ist, das alle Werte der bereitgestellten Arrays enthält: $indirect[$i] = [$v1, $v2, $v3, ..., NULL]. Dann wird QuickSort auf das Array angewendet, indem eine spezielle Vergleichsfunktion verwendet wird, die zuerst vergleicht $indirect[$a][$r] zu $indirect[$b][$r] wo $r==0 wenn sie gleich sind, $r wird erhöht bis $indirect[$a][$r] ist null (alle bereitgestellten Arrays wurden verwendet). Schließlich wird jedes Array entsprechend umgeschrieben $indirect. Wenn Sie Arrays unterschiedlicher Größe verwenden, wird FALSE zurückgegeben.

    – 2072

    26. Juni 2014 um 20:05 Uhr

  • @dearsina: Guter Punkt. Das OP bezog sich jedoch speziell auf Zeichenfolgenschlüssel. Tatsächlich forderte er, dass “alle Tags, die den gleichen numerischen Wert haben … alphabetisch sortiert werden”.

    – Jon Bernhardt

    20. Dezember 2018 um 14:10 Uhr

Benutzeravatar von SlappyTheFish
SlappyTheFish

Sehen Sie sich Beispiel Nr. 3 an:
http://php.net/manual/en/function.array-multisort.php

Sie müssen zwei Arrays erstellen, die Sie als Indizes verwenden können. eine besteht aus den Schlüsseln des ursprünglichen Arrays und die andere aus den Werten des ursprünglichen Arrays.

Verwenden Sie dann Multisort, um nach Textwerten (Schlüsseln des ursprünglichen Arrays) und dann nach den numerischen Werten (Werten des ursprünglichen Arrays) zu sortieren.

  • @MMior Also, was ist die unkomplizierte Lösung?

    – Déjà-vu

    12. Juni 2011 um 10:47 Uhr

  • siehe @Jon Bernhardt unten für ein nettes Implementierungsbeispiel.

    – d.raev

    9. Oktober 2013 um 12:37 Uhr

Davids Benutzeravatar
David

GELÖST

Nach ein wenig experimentieren habe ich das festgestellt array_multisort macht den Trick gut:

$tag = array(); 
$num = array();

foreach($arrTags as $key => $value){ 
$tag[] = $key; 
$num[] = $value; 
}

array_multisort($num, SORT_DESC, $tag, SORT_ASC, $arrTags);

🙂

  • Das wäre die Antwort von SlappyTheFish, richtig? Ich denke, Sie sollten diese Antwort als akzeptiert markieren und sich dann die Funktionen array_keys() und array_values() ansehen, um Ihre Schleife loszuwerden.

    – Scott Saunders

    17. Februar 2010 um 18:53 Uhr

  • Auch ein Hinweis für zukünftige Besucher: $tag = array_keys( $arrTags); $num = array_values( $arrTags); würde die identischen Arrays ohne Schleife bilden.

    – Nickb

    8. April 2013 um 20:27 Uhr


  • Warum funktioniert das bei mir nicht? Ich kopiere das obige Beispiel und die Lösung habe gerade das gleiche Ergebnis in der Frage.

    – Tim Yao

    1. Dezember 2014 um 3:06 Uhr

  • @TimYao könnte es sein, dass deine Schlüssel numerisch sind? 3v4l.org/uUYUO

    – Liebesina

    19. Dezember 2018 um 6:44 Uhr

Benutzeravatar von Sijmen Ruwhof
Sijmen Ruwhof

Der vorherige Lösungsvorschlag erscheint logisch, funktioniert aber einfach nicht:

ksort($arrTags);
arsort($arrTags);

Der vollständige PHP-Code, um die gewünschte Sortierung zu realisieren, wird sein:

$k = array_keys($arrTags);
$v = array_values($arrTags);
array_multisort($k, SORT_ASC, $v, SORT_DESC);
$arrTags = array_combine($k, $v);

Bitte beachten Sie, dass array_multisort() Referenzen auf Benutzereingaben verwendet, sodass Sie zwei temporäre Variablen ($k und $v) verwenden müssen, um Inhalt als Benutzereingabe bereitzustellen. Auf diese Weise kann array_multisort() den Inhalt ändern. Bauen Sie später das sortierte Array über array_combine() neu auf.

Ich habe eine wiederverwendbare Funktion erstellt, um diese Aufgabe zu erfüllen:

<?php
/**
 * Sort a multi-dimensional array by key, then by value.
 *
 * @param array Array to be sorted
 * @param int One of the available sort options: SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
 * @param int One of the available sort options: SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
 * @return void
 * @example The following array will be reordered:
 *  $a = array(
 *      'd' => 4,
 *      'c' => 2,
 *      'a' => 3,
 *      'b' => 1,
 *      'e' => 2,
 *      'g' => 2,
 *      'f' => 2,
 *  );
 *  SortArrayByKeyThanValue($a);        # reorder array to: array(
 *      'b' => 1,
 *      'c' => 2,
 *      'e' => 2,
 *      'f' => 2,
 *      'g' => 2,
 *      'a' => 3,
 *      'd' => 4,
 *  );
 * @author Sijmen Ruwhof <sijmen(a)secundity.com>
 * @copyright 2011, Secundity
 */
function SortArrayByKeyThanValue (&$pArray, $pSortMethodForKey = SORT_ASC, $pSortMethodForValue = SORT_ASC)
{
    # check user input: sorting is not necessary
    if (count($pArray) < 2)
        return;

    # define $k and $v as array_multisort() needs real variables, as user input is put by reference
    $k = array_keys  ($pArray);
    $v = array_values($pArray);

    array_multisort(
        $v, $pSortMethodForValue,
        $k, $pSortMethodForKey
    );
    $pArray = array_combine($k, $v);
}
?>

SlappyTheFish ist richtig bezüglich: Verwendung von array_multisort vs. ksort, arsort

In Davids Beispiel ksort funktioniert arsort gut, aber wenn die Zeichenfolgenwerte der Schlüssel andere Zeichen als alphabetische Zeichen enthalten, funktioniert die Sortierung möglicherweise nicht wie beabsichtigt.

ex:

$arrTags['banana'] = 3;
$arrTags['mango'] = 2;
$arrTags['apple1'] = 2;
$arrTags['orange'] = 4;
$arrTags['almond1'] = 2;

ksort($arrTags);
arsort($arrTags);

print_r($arrTags);

kehrt zurück:

Array
(
    [orange] => 4
    [banana] => 3
    [apple1] => 2
    [mango] => 2
    [almond1] => 2
)

jedoch mit:

$arrTags['banana'] = 3;
$arrTags['mango'] = 2;
$arrTags['apple1'] = 2;
$arrTags['orange'] = 4;
$arrTags['almond1'] = 2;

$tag = array();
$num = array();

foreach($arrTags as $key => $value){
    $tag[] = $key;
    $num[] = $value;
}

array_multisort($num, SORT_DESC, $tag, SORT_ASC, $arrTags);


print_r($arrTags);

kehrt zurück:

Array
(
    [orange] => 4
    [banana] => 3
    [almond1] => 2
    [apple1] => 2
    [mango] => 2
)

  • Diese Antwort ist irreführend und nicht mehr aktuell. Ab PHP7 und höher, ksort() then arsort() wird das Array richtig sortieren. Es ist der Sortieralgorithmus vor PHP7, der die Technik unzuverlässig gemacht hat. Wichtig ist, dass dieses unterschiedliche Verhalten nichts mit Zahlen zu tun hat, die in den Schlüsseln vorhanden sind. Sehen Sie sich diese Demo an: 3v4l.org/d3a1m Bitte aktualisieren Sie Ihre Antwort, damit sie korrekt und aktuell ist. Im Moment wird der einzige Teil Ihrer Antwort, der richtig/wahr ist, von stackoverflow.com/a/2282247/2943403 kopiert

    – mickmackusa

    15. Dezember 2020 um 22:32 Uhr


  • Ihr letztes Snippet hätte prägnanter sein können: 3v4l.org/8UcaZ oder noch präziser, verwenden Sie keine Schleife: 3v4l.org/pXl20

    – mickmackusa

    22. September um 6:10 Uhr


Benutzeravatar von Sid
Sid

//preserve arrays keys for later use
$ar1= array_keys($your_array);

//preserve array's values for later use
$ar2= array_values($your_array);

//perform sorting by value and then by key
array_multisort($ar2, SORT_DESC, $ar1, SORT_DESC);

//combine sorted values and keys arrays to new array
$sorted_array = array_combine($ar1, $ar2);

Muss in Ordnung sein.

  • Diese Antwort ist irreführend und nicht mehr aktuell. Ab PHP7 und höher, ksort() then arsort() wird das Array richtig sortieren. Es ist der Sortieralgorithmus vor PHP7, der die Technik unzuverlässig gemacht hat. Wichtig ist, dass dieses unterschiedliche Verhalten nichts mit Zahlen zu tun hat, die in den Schlüsseln vorhanden sind. Sehen Sie sich diese Demo an: 3v4l.org/d3a1m Bitte aktualisieren Sie Ihre Antwort, damit sie korrekt und aktuell ist. Im Moment wird der einzige Teil Ihrer Antwort, der richtig/wahr ist, von stackoverflow.com/a/2282247/2943403 kopiert

    – mickmackusa

    15. Dezember 2020 um 22:32 Uhr


  • Ihr letztes Snippet hätte prägnanter sein können: 3v4l.org/8UcaZ oder noch präziser, verwenden Sie keine Schleife: 3v4l.org/pXl20

    – mickmackusa

    22. September um 6:10 Uhr


Verwenden uksort() um die Schlüssel in den Bereich der benutzerdefinierten Funktion zu übergeben; Greifen Sie innerhalb dieses Bereichs auf den zugeordneten Wert zu, indem Sie den Schlüssel für das übergebene (vollständige) Array verwenden.

Der Vorteil davon ist die zeitliche Komplexität – dies ist direkter als zwei separate Sortierfunktionsaufrufe und erfordert keine Einrichtung von array_multisort(). Ebenfalls, array_multisort() wird numerische Tasten zerstören (nicht, dass die Tasten des Fragestellers numerisch sind) https://3v4l.org/rQak4.

Obwohl der Raumschiff-Operator (3-Wege) damals noch nicht verfügbar war, als diese Frage gestellt wurde, ist er es jetzt und macht den Vergleich jetzt viel einfacher/sauberer.

Ab PHP7.4 ist die Syntax sehr prägnant. (Demo)

uksort($arrTags, fn($a, $b) => [$arrTags[$b], $a] <=> [$arrTags[$a], $b]);

Von PHP7.0 – PHP7.3 müssen Sie das Hauptarray mit übergeben use(). (Demo)

uksort(
    $arrTags,
    function($a, $b) use ($arrTags) {
        return [$arrTags[$b], $a] <=> [$arrTags[$a], $b];
    }
);

1430660cookie-checkSortieren Sie ein flaches, assoziatives Array nach numerischen Werten und dann nach nicht numerischen Schlüsseln

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy