it-swarm.com.de

Wie sortiere ich ein mehrdimensionales Array in PHP

Ich habe CSV-Daten in ein mehrdimensionales Array geladen. Auf diese Weise ist jede "Zeile" ein Datensatz und jede "Spalte" enthält den gleichen Datentyp. Ich benutze die unten stehende 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 Y-m-d H:i:s und ich möchte in der Lage sein, mit dem letzten Datum zu sortieren, das die erste Reihe ist.

197
Melikoth

Sie können array_multisort () verwenden

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. Die Schleife ist nicht erforderlich:

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

Einführung: 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 wie Sie möchten) - zusätzliche Spalten werden als Tiebreaker zwischen Elementen verwendet, die anfänglich gleich sind.
  3. Es ist umkehrbar : Sie können festlegen, dass die Sortierung umgekehrt werden soll - individuell für jede Spalte.
  4. Es ist erweiterbar : Wenn der Datensatz Spalten enthält, die nicht "dumm" verglichen werden können (z. B. Datumszeichenfolgen), können Sie auch angeben, wie diese konvertiert werden sollen Elemente mit einem Wert, der direkt verglichen werden kann (z. B. eine DateTime -Instanz).
  5. Es ist assoziativ, wenn Sie möchten : Dieser Code kümmert sich um das Sortieren von Elementen, aberSiewählen die tatsächliche Sortierfunktion (usort oder uasort).
  6. Schließlich wird array_multisort Nicht verwendet: Während array_multisort Praktisch ist, hängt es davon ab, dass Sie vor dem Sortieren eine Projektion aller Ihrer Eingabedaten erstellen. Dies kostet Zeit und Speicher und ist möglicherweise unerschwinglich, wenn Ihre Datenmenge 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 für usort oder uasort verwenden sollen.

Der einfachste Anwendungsfall ist die Übergabe des Schlüssels, den Sie zum Vergleichen von Datenelementen verwenden möchten. Zum Beispiel, um $data Nach dem name Element zu sortieren, das Sie tun würden

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

In Aktion sehen.

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

In Aktion sehen.

Mehrere Sortierspalten

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

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

In Aktion sehen.

Erweiterte Funktionen

Erweiterte Funktionen sind verfügbar, wenn Sie anstelle einer einfachen Zeichenfolge eine Sortierspalte als Array angeben. Dieses Array sollte numerisch indiziert sein und folgende 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.

Sortierung umkehren

So sortieren Sie nach absteigendem Namen:

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

In Aktion sehen.

So sortieren Sie nach absteigender Nummer und anschließend nach absteigendem Namen:

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

In Aktion sehen.

Kundenspezifische 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 ist nicht sinnvoll, Geburtstage als Zeichenfolgen zu vergleichen (da beispielsweise "01.01.1980" vor "10.10.1970" steht). In diesem Fall möchten wir festlegen, wieprojiziertdie tatsächlichen Daten in eine Form, mit derdirekt verglichen werden kanndie gewünschte Semantik.

Projektionen können als jede Art von aufrufbar : als Zeichenfolgen, Arrays oder anonyme Funktionen angegeben werden. Es wird angenommen, dass eine Projektion ein Argument akzeptiert und seine projizierte Form zurückgibt.

Es ist zu beachten, dass Projektionen zwar den benutzerdefinierten Vergleichsfunktionen für usort und family ähneln, diese jedoch einfacher sind (Sie müssen nur einen Wert in einen anderen konvertieren) und alle Funktionen nutzen, die bereits in make_comparer.

Sortieren wir den Beispieldatensatz ohne Projektion und sehen, was passiert:

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

In Aktion sehen.

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

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

In Aktion sehen.

Dies ist die richtige Reihenfolge, die wir wollten.

Es gibt viel mehr Dinge, die Projektionen erreichen können. Eine schnelle Möglichkeit, eine Sortierung ohne Berücksichtigung der Groß- und Kleinschreibung zu erhalten, besteht beispielsweise darin, strtolower als Projektion zu verwenden.

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 zu sortieren, ohne eine Projektion zu verwenden, obwohl dies den Handel beeinträchtigt Erhöhte Speichernutzung für schnellere Sortiergeschwindigkeit.

Schließlich ist hier ein Beispiel, das alle Funktionen verwendet: Es wird zuerst nach absteigender Nummer und dann nach aufsteigendem Geburtstag sortiert:

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

In Aktion sehen.

341
Jon

Mit sort . 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);
31
troelskn

Mehrzeilige Sortierung mit einem Verschluss

Hier ist ein weiterer Ansatz mit uasort () und einer anonymen Rückruffunktion (Closure). Ich habe diese Funktion regelmäßig verwendet. 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' ) );
10
feeela

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 (dh 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

7
Mike C
function cmp($a, $b)
{
$p1 = $a['price'];
$p2 = $b['price'];
return (float)$p1 > (float)$p2;
}
uasort($my_array, "cmp");

http://qaify.com/sort-an-array-of-associative-arrays-by-value-of-given-key-in-php/

6
Kamal

Die "Usort" -Funktion ist Ihre Antwort.
http://php.net/usort

3
Jan Hančič

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

Bevor ich die TableSorter-Klasse zum Laufen bringen konnte, hatte ich mir eine Funktion ausgedacht, die auf dem basiert, was Shinhan bereitgestellt hatte.

function sort2d_bycolumn($array, $column, $method, $has_header)
  {
  if ($has_header)  $header = array_shift($array);
  foreach ($array as $key => $row) {
    $narray[$key]  = $row[$column]; 
    }
  array_multisort($narray, $method, $array);
  if ($has_header) array_unshift($array, $header);
  return $array;
  }
  • $ array ist das MD-Array, das Sie sortieren möchten.
  • $ column ist die Spalte, nach der Sie sortieren möchten.
  • Mit der Methode $ möchten Sie die Sortierung durchführen, z. B. SORT_DESC
  • $ has_header wird auf true gesetzt, wenn die erste Zeile Headerwerte enthält, die nicht sortiert werden sollen.
0
Melikoth

Ich habe mehrere beliebte array_multisort () und usort () Antworten ausprobiert und keine davon hat für mich funktioniert. Die Daten werden nur durcheinander gebracht und der Code ist nicht lesbar. Hier ist eine schnelle und schmutzige Lösung. WARNUNG: Verwenden Sie dies nur, wenn Sie sicher sind, dass ein Schurkenbegrenzer nicht zurückkommt, um Sie später zu verfolgen!

Angenommen, jede Zeile in Ihrem Multi-Array sieht folgendermaßen aus: name, stuff1, stuff2:

// Sort by name, pull the other stuff along for the ride
foreach ($names_stuff as $name_stuff) {
    // To sort by stuff1, that would be first in the contatenation
    $sorted_names[] = $name_stuff[0] .','. name_stuff[1] .','. $name_stuff[2];
}
sort($sorted_names, SORT_STRING);

Benötigen Sie Ihre Artikel wieder in alphabetischer Reihenfolge?

foreach ($sorted_names as $sorted_name) {
    $name_stuff = explode(',',$sorted_name);
    // use your $name_stuff[0] 
    // use your $name_stuff[1] 
    // ... 
}

Ja, es ist schmutzig. Aber super einfach, lässt deinen Kopf nicht explodieren.

0
PJ Brunet