Wie sortiere ich ein mehrdimensionales Array in PHP [duplicate]

Lesezeit: 13 Minuten

Wie sortiere ich ein mehrdimensionales Array in PHP duplicate
Melikoth

Ich habe CSV-Daten in ein mehrdimensionales Array geladen. Auf diese Weise ist jede “Zeile” ein Datensatz und jede “Spalte” enthält denselben Datentyp. Ich verwende die folgende Funktion, um meine CSV-Datei zu laden.

function f_parse_csv($file, $longest, $delimiter)
{
  $mdarray = array();
  $file    = fopen($file, "r");
  while ($line = fgetcsv($file, $longest, $delimiter))
  {
    array_push($mdarray, $line);
  }
  fclose($file);
  return $mdarray;
}

Ich muss in der Lage sein, eine zu sortierende Spalte anzugeben, damit die Zeilen neu angeordnet werden. Eine der Spalten enthält Datumsinformationen im Format von Y-m-d H:i:s und ich möchte in der Lage sein, mit dem neuesten Datum in der ersten Zeile zu sortieren.

  • (2 Jahre später …) Wenn Sie Daten sortieren, die als Zeichenfolgen gespeichert sind, müssen Sie möglicherweise zuerst strtotime verwenden [1] docs.php.net/manual/en/function.strtotime.php

    – Dan Burton

    19. Mai 2010 um 18:33 Uhr


  • @deceze, stackoverflow.com/q/1597736/1709587 scheint mir ein besseres Dupe-Ziel zu sein. Es ist ein genaueres Duplikat und die Antworten dort kommen folglich schneller auf den Punkt als Ihre unter stackoverflow.com/a/17364128/1709587, während sie insgesamt den gleichen Detailgrad haben. Was sagt ihr zum Zielwechsel? (Offenlegung: Ich bin möglicherweise als Autor einer der Antworten auf das von mir vorgeschlagene betrügerische Ziel voreingenommen.)

    – Mark Amery

    29. Juni 2019 um 16:34 Uhr


  • Siehe auch: stackoverflow.com/questions/1597736/…

    – dreftymac

    29. Juli 2019 um 21:30 Uhr

Wie sortiere ich ein mehrdimensionales Array in PHP duplicate
Jon

Wir stellen vor: eine sehr verallgemeinerte Lösung für PHP 5.3+

Ich möchte hier meine eigene Lösung hinzufügen, da sie Funktionen bietet, die andere Antworten nicht bieten.

Zu den Vorteilen dieser Lösung gehören insbesondere:

  1. Es ist wiederverwendbar: Sie geben die Sortierspalte als Variable an, anstatt sie fest zu codieren.
  2. Es ist flexibel: Sie können mehrere Sortierspalten angeben (so viele Sie möchten) – zusätzliche Spalten werden als Tiebreaker zwischen Elementen verwendet, die anfänglich gleich verglichen werden.
  3. Es ist reversibel: Sie können angeben, dass die Sortierung umgekehrt werden soll – individuell für jede Spalte.
  4. Es ist erweiterbar: Wenn der Datensatz Spalten enthält, die nicht auf “dumme” Weise verglichen werden können (z. B. Datumszeichenfolgen), können Sie auch angeben, wie diese Elemente in einen direkt vergleichbaren Wert konvertiert werden sollen (z. B. a DateTime Beispiel).
  5. Es ist assoziativ, wenn Sie wollen: Dieser Code kümmert sich um das Sortieren von Artikeln, aber Sie Wählen Sie die aktuelle Sortierfunktion (usort oder uasort).
  6. Schließlich nutzt es nicht array_multisort: während array_multisort bequem ist, hängt es davon ab, vor dem Sortieren eine Projektion aller Ihrer Eingabedaten zu erstellen. Dies verbraucht Zeit und Speicherplatz und kann einfach unerschwinglich sein, wenn Ihr Datensatz groß ist.

Der Code

function make_comparer() {
    // Normalize criteria up front so that the comparer finds everything tidy
    $criteria = func_get_args();
    foreach ($criteria as $index => $criterion) {
        $criteria[$index] = is_array($criterion)
            ? array_pad($criterion, 3, null)
            : array($criterion, SORT_ASC, null);
    }

    return function($first, $second) use (&$criteria) {
        foreach ($criteria as $criterion) {
            // How will we compare this round?
            list($column, $sortOrder, $projection) = $criterion;
            $sortOrder = $sortOrder === SORT_DESC ? -1 : 1;

            // If a projection was defined project the values now
            if ($projection) {
                $lhs = call_user_func($projection, $first[$column]);
                $rhs = call_user_func($projection, $second[$column]);
            }
            else {
                $lhs = $first[$column];
                $rhs = $second[$column];
            }

            // Do the actual comparison; do not return if equal
            if ($lhs < $rhs) {
                return -1 * $sortOrder;
            }
            else if ($lhs > $rhs) {
                return 1 * $sortOrder;
            }
        }

        return 0; // tiebreakers exhausted, so $first == $second
    };
}

Wie benutzt man

In diesem Abschnitt werde ich Links bereitstellen, die diesen Beispieldatensatz sortieren:

$data = array(
    array('zz', 'name' => 'Jack', 'number' => 22, 'birthday' => '12/03/1980'),
    array('xx', 'name' => 'Adam', 'number' => 16, 'birthday' => '01/12/1979'),
    array('aa', 'name' => 'Paul', 'number' => 16, 'birthday' => '03/11/1987'),
    array('cc', 'name' => 'Helen', 'number' => 44, 'birthday' => '24/06/1967'),
);

Die Grundlagen

Die Funktion make_comparer akzeptiert eine variable Anzahl von Argumenten, die die gewünschte Sortierung definieren, und gibt eine Funktion zurück, die Sie als Argument verwenden sollen usort oder uasort.

Der einfachste Anwendungsfall besteht darin, den Schlüssel zu übergeben, den Sie zum Vergleichen von Datenelementen verwenden möchten. Zum Beispiel sortieren $data bis zum name Artikel, den Sie tun würden

usort($data, make_comparer('name'));

Sehen Sie es in Aktion.

Der Schlüssel kann auch eine Zahl sein, wenn die Elemente numerisch indizierte Arrays sind. Für das Beispiel in der Frage wäre dies

usort($data, make_comparer(0)); // 0 = first numerically indexed column

Sehen Sie es in Aktion.

Mehrere Sortierspalten

Sie können mehrere Sortierspalten angeben, indem Sie zusätzliche Parameter an übergeben make_comparer. So sortieren Sie beispielsweise nach “Nummer” und dann nach der mit Null indizierten Spalte:

usort($data, make_comparer('number', 0));

Sehen Sie es in Aktion.

Erweiterte Funktionen

Erweiterte Funktionen sind verfügbar, wenn Sie eine Sortierspalte als Array anstelle einer einfachen Zeichenfolge angeben. Dieses Array sollte numerisch indiziert sein und diese Elemente enthalten:

0 => the column name to sort on (mandatory)
1 => either SORT_ASC or SORT_DESC (optional)
2 => a projection function (optional)

Mal sehen, wie wir diese Funktionen nutzen können.

Umgekehrte Sortierung

Absteigend nach Namen sortieren:

usort($data, make_comparer(['name', SORT_DESC]));

Sehen Sie es in Aktion.

So sortieren Sie nach Nummer absteigend und dann nach Namen absteigend:

usort($data, make_comparer(['number', SORT_DESC], ['name', SORT_DESC]));

Sehen Sie es in Aktion.

Benutzerdefinierte Projektionen

In einigen Szenarien müssen Sie möglicherweise nach einer Spalte sortieren, deren Werte sich nicht gut zum Sortieren eignen. Die Spalte „Geburtstag“ im Beispieldatensatz passt zu dieser Beschreibung: Es macht keinen Sinn, Geburtstage als Zeichenfolgen zu vergleichen (weil zB „01.01.1980“ vor „10.10.1970“ steht). In diesem Fall möchten wir angeben, wie Projekt die eigentlichen Daten in ein Formular, das kann direkt mit der gewünschten Semantik verglichen werden.

Projektionen können als beliebiger Typ angegeben werden abrufbar: als Strings, Arrays oder anonyme Funktionen. Es wird angenommen, dass eine Projektion ein Argument akzeptiert und seine projizierte Form zurückgibt.

Es sollte beachtet werden, dass zwar Projektionen den benutzerdefinierten Vergleichsfunktionen ähneln, die mit verwendet werden usort und Familie, sie sind einfacher (Sie müssen nur einen Wert in einen anderen umwandeln) und nutzen alle bereits eingebauten Funktionen make_comparer.

Lassen Sie uns den Beispieldatensatz ohne Projektion sortieren und sehen, was passiert:

usort($data, make_comparer('birthday'));

Sehen Sie es in Aktion.

Das war nicht das gewünschte Ergebnis. Aber wir können verwenden date_create als Projektion:

usort($data, make_comparer(['birthday', SORT_ASC, 'date_create']));

Sehen Sie es in Aktion.

Dies ist die richtige Reihenfolge, die wir wollten.

Es gibt noch viel mehr Dinge, die Projektionen erreichen können. Eine schnelle Möglichkeit, eine Sortierung ohne Berücksichtigung der Groß-/Kleinschreibung zu erhalten, ist z. B. use strtolower als Projektion.

Allerdings sollte ich auch erwähnen, dass es besser ist, keine Projektionen zu verwenden, wenn Ihr Datensatz groß ist: In diesem Fall wäre es viel schneller, alle Ihre Daten manuell im Voraus zu projizieren und dann ohne Verwendung einer Projektion zu sortieren, obwohl dies der Fall wäre erhöhte Speichernutzung für schnellere Sortiergeschwindigkeit.

Zum Schluss noch ein Beispiel, das alle Features nutzt: Es sortiert erst nach Nummer absteigend, dann nach Geburtstag aufsteigend:

usort($data, make_comparer(
    ['number', SORT_DESC],
    ['birthday', SORT_ASC, 'date_create']
));

Sehen Sie es in Aktion.

  • @Jon – Danke für all deine Hilfe. Ich habe versucht, dies auf meinem Server zu implementieren, und ich bekomme Folgendes: PHP-Parse-Fehler: Syntaxfehler, unerwartet ‘[‘, expecting ‘)’ — I tried different variation, I’m just a bit lost on how this really works. I’m on v5.3.28 – ideone.com runs php 5.4 – is that the issue?

    – Ecropolis

    Jun 5, 2014 at 20:34

  • @Ecropolis: PHP 5.3 does not support the short [...] Array-Syntax, müssen Sie verwenden array(...) stattdessen. Ich habe das in den Beispielen der Kürze halber nicht gemacht, aber make_comparer selbst ist kompatibel mit 5.3.

    – Jon

    5. Juni 2014 um 20:49 Uhr


  • @ Jon Tolle Antwort und ich stimme zu, dass dies eher eine Website als eine Antwort ist. Danke. Habe nur eine Frage. Wie kann ich es zum Laufen bringen, um nach Objekten zu rennen?

    – YahyaE

    3. Oktober 2014 um 21:21 Uhr

  • @YahyaE: Arrays von Objekten sortieren? Ersetzen $first[$column] mit $first->$columnund dasselbe für $second. Insgesamt vier Auswechslungen.

    – Jon

    10. Oktober 2014 um 0:02 Uhr


  • @CalculatingMachine Ich habe die Frage gelesen, aber Sie zeigen nicht, was Sie versucht haben. Es scheint gerecht usort($data['content'], get_comparer('price')) würde reichen, bin mir aber nicht sicher.

    – Jon

    22. April 2016 um 9:00 Uhr

Wie sortiere ich ein mehrdimensionales Array in PHP duplicate
Shinhan

Sie können verwenden array_multisort()

Versuchen Sie so etwas:

foreach ($mdarray as $key => $row) {
    // replace 0 with the field's index/key
    $dates[$key]  = $row[0];
}

array_multisort($dates, SORT_DESC, $mdarray);

Für PHP >= 5.5.0 extrahieren Sie einfach die Spalte, nach der sortiert werden soll. Keine Notwendigkeit für die Schleife:

array_multisort(array_column($mdarray, 0), SORT_DESC, $mdarray);

  • In diesem Beispiel könnte $mdarray also ein zweidimensionales Array sein, etwa ein Array von Datenbankeinträgen. In diesem Beispiel ist 0 der Index der Spalte „Datum“ in jedem Datensatz (oder jeder Zeile). Sie konstruieren also das Array $dates (im Grunde das gleiche Array, aber nur mit dieser Spalte) und weisen die Funktion array_multisort an, $mdarray basierend auf den Werten dieser bestimmten Spalte zu sortieren.

    – Dan Burton

    19. Mai 2010 um 18:26 Uhr

  • Zur Verdeutlichung können Sie am Anfang dieses Beispiels etwas hinzufügen $dates = array();

    – Dan Burton

    19. Mai 2010 um 18:27 Uhr

  • Soll array_multisort mit assoziativen Arrays funktionieren (ändern $row[0] zu $row['whatever']? Gehen Sie hier nicht. Nachdem ich mein Array in numerisch geändert hatte, funktionierte die Funktion wie erwartet.

    – ein Codierer

    14. Februar 2013 um 22:24 Uhr

  • Ist nicht die Einbeziehung der $key unnötig bei der Nutzung array_multisort()? Es scheint einfacher und beabsichtigter zu schreiben foreach ($mdarray as $row) { $sortByDate[] = $row['date']; } dann array_multisort( $sortByDate, SORT_DESC, $mdarray ); (Ihre semantische Laufleistung kann variieren).

    – Markus Fuchs

    13. März 2013 um 21:02 Uhr

  • Wenn array_multi_sort() ist die Antwort, die Frage wurde nicht verstanden. Obwohl es technisch funktionieren wird, gibt es normalerweise eine bessere Lösung mit einer benutzergenerierten Vergleichsfunktion und der Verwendung von a usort() Funktion. Es ist einfacher zu pflegen. Bei Multisort erstellen Sie normalerweise Code, der die Daten für die Sortierung vorbereitet. Wenn sich die Datenstruktur ändert, wird dieser Code möglicherweise verworfen. Mit usort() ändern Sie die Vergleichsfunktion – genauso wie Sie die Datenstruktur geändert haben.

    – Sven

    17. Juli 2013 um 7:54 Uhr

Mit usort. Hier ist eine generische Lösung, die Sie für verschiedene Spalten verwenden können:

class TableSorter {
  protected $column;
  function __construct($column) {
    $this->column = $column;
  }
  function sort($table) {
    usort($table, array($this, 'compare'));
    return $table;
  }
  function compare($a, $b) {
    if ($a[$this->column] == $b[$this->column]) {
      return 0;
    }
    return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
  }
}

So sortieren Sie nach der ersten Spalte:

$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);

  • Ich erhalte einen Parse-Fehler: Parse-Fehler, unerwarteter T_STRING, erwartet T_OLD_FUNCTION oder T_FUNCTION oder T_VAR oder ‘}’ in der zweiten Zeile dieser Klasse.

    – Melikot

    18. September 2008 um 21:35 Uhr

  • Ersetzen Sie “protected” durch “var” und “__construct” durch “TableSorter”, und es funktioniert in PHP4. Beachten Sie jedoch, dass PHP4 eingestellt wurde.

    – troelskn

    18. September 2008 um 22:23 Uhr

  • Ich habe PHP auf v5 gesetzt, wusste nicht, dass es standardmäßig v4 ausführt. Nachdem ich es mir eine Weile angeschaut habe, glaube ich zu verstehen, wie man es auch für verschiedene Arten von Sorten modifiziert

    – Melikot

    18. September 2008 um 23:19 Uhr

Mehrreihiges Sortieren mit Closure

Hier ist ein weiterer Ansatz mit uasort() und einer anonymen Callback-Funktion (Closure). Ich habe diese Funktion regelmäßig genutzt. PHP 5.3 erforderlich – keine Abhängigkeiten mehr!

/**
 * Sorting array of associative arrays - multiple row sorting using a closure.
 * See also: http://the-art-of-web.com/php/sortarray/
 *
 * @param array $data input-array
 * @param string|array $fields array-keys
 * @license Public Domain
 * @return array
 */
function sortArray( $data, $field ) {
    $field = (array) $field;
    uasort( $data, function($a, $b) use($field) {
        $retval = 0;
        foreach( $field as $fieldname ) {
            if( $retval == 0 ) $retval = strnatcmp( $a[$fieldname], $b[$fieldname] );
        }
        return $retval;
    } );
    return $data;
}

/* example */
$data = array(
    array( "firstname" => "Mary", "lastname" => "Johnson", "age" => 25 ),
    array( "firstname" => "Amanda", "lastname" => "Miller", "age" => 18 ),
    array( "firstname" => "James", "lastname" => "Brown", "age" => 31 ),
    array( "firstname" => "Patricia", "lastname" => "Williams", "age" => 7 ),
    array( "firstname" => "Michael", "lastname" => "Davis", "age" => 43 ),
    array( "firstname" => "Sarah", "lastname" => "Miller", "age" => 24 ),
    array( "firstname" => "Patrick", "lastname" => "Miller", "age" => 27 )
);

$data = sortArray( $data, 'age' );
$data = sortArray( $data, array( 'lastname', 'firstname' ) );

Ich weiß, es ist 2 Jahre her, seit diese Frage gestellt und beantwortet wurde, aber hier ist eine andere Funktion, die ein zweidimensionales Array sortiert. Es akzeptiert eine variable Anzahl von Argumenten, sodass Sie mehr als einen Schlüssel (z. B. Spaltennamen) zum Sortieren übergeben können. PHP 5.3 erforderlich.

function sort_multi_array ($array, $key)
{
  $keys = array();
  for ($i=1;$i<func_num_args();$i++) {
    $keys[$i-1] = func_get_arg($i);
  }

  // create a custom search function to pass to usort
  $func = function ($a, $b) use ($keys) {
    for ($i=0;$i<count($keys);$i++) {
      if ($a[$keys[$i]] != $b[$keys[$i]]) {
        return ($a[$keys[$i]] < $b[$keys[$i]]) ? -1 : 1;
      }
    }
    return 0;
  };

  usort($array, $func);

  return $array;
}

Versuchen Sie es hier: http://www.exorithm.com/algorithm/view/sort_multi_array

  • Könnten die ersten 3 Zeilen der Funktion durch ersetzt werden $keys = func_get_args(); array_unshift($keys);?

    Benutzer212218

    13. März 2012 um 18:44 Uhr

Sie können ein Array mit sortieren usort Funktion.

 $array = array(
  array('price'=>'1000.50','product'=>'product 1'),
  array('price'=>'8800.50','product'=>'product 2'),
  array('price'=>'200.0','product'=>'product 3')
);

function cmp($a, $b) {
  return $a['price'] > $b['price'];
}
usort($array, "cmp");
print_r($array);

Ausgabe :

Array
(
    [0] => Array
        (
            [price] => 134.50
            [product] => product 1
        )

    [1] => Array
        (
            [price] => 2033.0
            [product] => product 3
        )

    [2] => Array
        (
            [price] => 8340.50
            [product] => product 2
        )

)

Beispiel

  • Könnten die ersten 3 Zeilen der Funktion durch ersetzt werden $keys = func_get_args(); array_unshift($keys);?

    Benutzer212218

    13. März 2012 um 18:44 Uhr

1647063851 913 Wie sortiere ich ein mehrdimensionales Array in PHP duplicate
Devon

Hier ist eine php4/php5-Klasse, die ein oder mehrere Felder sortiert:

// a sorter class
//  php4 and php5 compatible
class Sorter {

  var $sort_fields;
  var $backwards = false;
  var $numeric = false;

  function sort() {
    $args = func_get_args();
    $array = $args[0];
    if (!$array) return array();
    $this->sort_fields = array_slice($args, 1);
    if (!$this->sort_fields) return $array();

    if ($this->numeric) {
      usort($array, array($this, 'numericCompare'));
    } else {
      usort($array, array($this, 'stringCompare'));
    }
    return $array;
  }

  function numericCompare($a, $b) {
    foreach($this->sort_fields as $sort_field) {
      if ($a[$sort_field] == $b[$sort_field]) {
        continue;
      }
      return ($a[$sort_field] < $b[$sort_field]) ? ($this->backwards ? 1 : -1) : ($this->backwards ? -1 : 1);
    }
    return 0;
  }

  function stringCompare($a, $b) {
    foreach($this->sort_fields as $sort_field) {
      $cmp_result = strcasecmp($a[$sort_field], $b[$sort_field]);
      if ($cmp_result == 0) continue;

      return ($this->backwards ? -$cmp_result : $cmp_result);
    }
    return 0;
  }
}

/////////////////////
// usage examples

// some starting data
$start_data = array(
  array('first_name' => 'John', 'last_name' => 'Smith', 'age' => 10),
  array('first_name' => 'Joe', 'last_name' => 'Smith', 'age' => 11),
  array('first_name' => 'Jake', 'last_name' => 'Xample', 'age' => 9),
);

// sort by last_name, then first_name
$sorter = new Sorter();
print_r($sorter->sort($start_data, 'last_name', 'first_name'));

// sort by first_name, then last_name
$sorter = new Sorter();
print_r($sorter->sort($start_data, 'first_name', 'last_name'));

// sort by last_name, then first_name (backwards)
$sorter = new Sorter();
$sorter->backwards = true;
print_r($sorter->sort($start_data, 'last_name', 'first_name'));

// sort numerically by age
$sorter = new Sorter();
$sorter->numeric = true;
print_r($sorter->sort($start_data, 'age'));

  • Funktioniert das nur mit assoziativen Arrays?

    – Melikot

    18. September 2008 um 23:23 Uhr

  • ja – nur assoziative Arrays. Jetzt, wo ich es mir ansehe, ist es nicht die richtige Lösung für dieses Problem.

    – Devon

    22. September 2008 um 20:54 Uhr

992820cookie-checkWie sortiere ich ein mehrdimensionales Array in PHP [duplicate]

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

Privacy policy