Sortieren Array von MultiDiminsional Arrays auf mehr als eine „Spalte“ (Key) Mit Angegebene Sortieroptionen

StackOverflow https://stackoverflow.com/questions/809771

Frage

Ich bin auf der Suche nach der Lage sein, eine Reihe von mehrdimensionalen Arrays auf mehr als eine Spalte zu sortieren. Um sie weiter komplizieren Ich möchte in der Lage sein zu setzen bestimmte Sortieroptionen pro Schlüssel / Spalte. Ich habe, was ähnlich ist das Ergebnis einer DB-Abfrage, ist aber nicht wirklich kommt aus einem, daher die Notwendigkeit, es in PHP zu sortieren, anstatt SQL.

Array
(
    [0] => Array
        (
            [first_name] => Homer
            [last_name] => Simpson
            [city] => Springfield
            [state] => Unknown
            [zip] => 66735
        )

    [1] => Array
        (
            [first_name] => Patty
            [last_name] => Bouvier
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85250
        )

    [2] => Array
        (
            [first_name] => Moe
            [last_name] => Szyslak
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

    [3] => Array
        (
            [first_name] => Nick
            [last_name] => Riviera
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

)

Ich möchte in der Lage sein, es zu sortieren, ähnlich dem, was mit einer DB-Abfrage durchgeführt werden konnte. Ach ja, und manchmal eine Spalte / Schlüssel muss nach Nummer angegeben werden.

Was ich im Sinn hatte, war so etwas wie folgt aus:

$sortOptions = array( array( 'city', SORT_ASC, SORT_STRING ),
                      array( 'zip', SORT_DESC, SORT_NUMERIC),
                      array( 2, SORT_ASC, SORT_STRING) // 2='last_name'
                    );
$sorter = new MultiSort($data, $sortOptions );
$sortedData = $sorter->getSortedArray() ;
print_r( $jmsSorted);

Was möchte ich mit am Ende ist dies:

Array
(
    [0] => Array
        (
            [first_name] => Nick
            [last_name] => Riviera
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

    [1] => Array
        (
            [first_name] => Moe
            [last_name] => Szyslak
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

    [2] => Array
        (
            [first_name] => Patty
            [last_name] => Bouvier
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85250
        )

    [3] => Array
        (
            [first_name] => Homer
            [last_name] => Simpson
            [city] => Springfield
            [state] => Unknown
            [zip] => 66735
        )

)

UPDATE: Ich denke, dass im Idealfall eine Lösung in dynamischer Erstellung führen würde

array_multisort( $city, SORT_ASC, SORT_STRING, $zip, SORT_DESC, SORT_NUMERIC, $last_name, SORT_ASC, SORT_STRING, $inputArray);

Das Problem ist, dass ich möchte nicht dort zu „harten Code“ diese Schlüsselnamen haben. Ich habe versucht, eine Lösung auf der Grundlage der Erstellung Beispiel # 3 Sortierung Datenbank Ergebnisse von der array_multisort() Dokumentation, die array_multisort() mit endete, aber ich kann mich nicht dynamisch aufgebaut Argumentliste für array_multisort() scheinen einen Weg zu finden, zu verwenden.

Mein Versuch war zu „Kette“ diese Argumente zusammen in ein Array und dann

call_user_func_array( 'array_multisort', $functionArgs);

Das ergibt ein

Warning: Parameter 2 to array_multisort() expected to be a reference, value given in...
War es hilfreich?

Lösung 4

Hier ist, was ich schließlich in der Lage, ließ sich auf mehrdimensionale Arrays zu sortieren. Beide Antworten oben sind gut, aber ich war auch auf der Suche nach etwas flexibler.

Ich glaube definitiv nicht, dass es irgendeine „richtige“ Antwort, aber das ist, was für meine Bedürfnisse arbeitet und flexibel ist.

Wie Sie aus meinem @link im Kommentar von _usortByMultipleKeys() sehen sie aus einem Kommentar in dem PHP-Handbuch angepasst wurden, die derzeit nicht zu existieren scheint, aber ich glaube, http://www.php.net/manual/en/function.usort.php#104398 ist eine neue Version von der ursprüngliche Kommentar. Ich habe nicht untersucht, dass neuen Vorschlag mit.

/**
 * Sort the resultSet.
 *
 * Usage: $sortOptions = array(
 *          'section', // Defaults to SORT_ASC
 *          'row' => SORT_DESC,
 *          'retail_price' => SORT_ASC);
 *        $results->sortResults($sortOptions);
 *
 * @param array $sortOptions    An array of sorting instructions
 */
public function sortResults(array $sortOptions)
{
    usort($this->_results, $this->_usortByMultipleKeys($sortOptions));
}


/**
 * Used by sortResults()
 *
 * @link http://www.php.net/manual/en/function.usort.php#103722
 */
protected function _usortByMultipleKeys($key, $direction=SORT_ASC)
{
    $sortFlags = array(SORT_ASC, SORT_DESC);
    if (!in_array($direction, $sortFlags)) {
        throw new InvalidArgumentException('Sort flag only accepts SORT_ASC or SORT_DESC');
    }
    return function($a, $b) use ($key, $direction, $sortFlags) {
        if (!is_array($key)) { //just one key and sort direction
            if (!isset($a->$key) || !isset($b->$key)) {
                throw new Exception('Attempting to sort on non-existent keys');
            }
            if ($a->$key == $b->$key) {
                return 0;
            }
            return ($direction==SORT_ASC xor $a->$key < $b->$key) ? 1 : -1;
        } else { //using multiple keys for sort and sub-sort
            foreach ($key as $subKey => $subAsc) {
                //array can come as 'sort_key'=>SORT_ASC|SORT_DESC or just 'sort_key', so need to detect which
                if (!in_array($subAsc, $sortFlags)) {
                    $subKey = $subAsc;
                    $subAsc = $direction;
                }
                //just like above, except 'continue' in place of return 0
                if (!isset($a->$subKey) || !isset($b->$subKey)) {
                    throw new Exception('Attempting to sort on non-existent keys');
                }
                if ($a->$subKey == $b->$subKey) {
                    continue;
                }
                return ($subAsc==SORT_ASC xor $a->$subKey < $b->$subKey) ? 1 : -1;
            }
            return 0;
        }
    };
}

Andere Tipps

In PHP 5.3 jeder Parameter in dem Array hat eine Referenz sein, wenn array_multisort() mit call_user_func_array() aufrufen.

Diese Funktion sortiert ein mehrdimensionales Array und zeigt einen Weg, um ein Array von referenzierten params zu bauen, die richtig funktioniert.

function msort()
{
  $params = func_get_args();
  $array = array_pop($params);

  if (!is_array($array))
    return false;

  $multisort_params = array();
  foreach ($params as $i => $param) 
  {
    if (is_string($param)) 
    {
      ${"param_$i"} = array();
      foreach ($array as $index => $row) 
      {
        ${"param_$i"}[$index] = $row[$param];
      }
    }
    else 
      ${"param_$i"} = $params[$i];

    $multisort_params[] = &${"param_$i"};
  }
  $multisort_params[] = &$array; 

  call_user_func_array("array_multisort", $multisort_params);

  return $array;
}

Beispiel:

$ data ist die gegebene Array von der Frage

$sorted_data = msort('city', SORT_ASC, SORT_STRING, 'zip', SORT_DESC, SORT_NUMERIC, $data)

Dies sollte für die Situation arbeiten Sie beschreiben.

usort($arrayToSort, "sortCustom");

function sortCustom($a, $b)
{
    $cityComp = strcmp($a['city'],$b['city']);
    if($cityComp == 0)
    {
        //Cities are equal.  Compare zips.
        $zipComp = strcmp($a['zip'],$b['zip']);
        if($zipComp == 0)
        {
            //Zips are equal.  Compare last names.
            return strcmp($a['last_name'],$b['last_name']);
        }
        else
        {
            //Zips are not equal.  Return the difference.
            return $zipComp;
        }
    }
    else
    {
        //Cities are not equal.  Return the difference.
        return $cityComp;
    }
}

Sie können es in einer Zeile wie so kondensieren:

function sortCustom($a, $b)
{
    return ($cityComp = strcmp($a['city'],$b['city']) ? $cityComp : ($zipComp = strcmp($a['zip'],$b['zip']) ? $zipComp : strcmp($a['last_name'],$b['last_name'])));
}

Was eine anpassbare Sortierfunktion, sind Sie das Rad neu zu erfinden. Werfen Sie einen Blick auf die array_multisort() Funktion.

Vielleicht möchten Sie versuchen Sie es mit usort . Alles, was Sie tun müssen, ist ein Funktionen machen, die den Sortierer sagen, wie es zu sortieren. Die docs haben mehr Informationen darüber, wie das zu tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top