7

複数の列で連想配列の配列をソートできるようにしたいと考えています。さらに複雑にするために、キー/列ごとに特定の並べ替えオプションを設定できるようにしたいと考えています。データベース クエリの結果セットに似た一連のデータがありますが、実際には 1 つのデータから得られたものではないため、SQL ではなく PHP で並べ替える必要があります。

[
    ['first_name' => 'Homer', 'last_name' => 'Simpson', 'city' => 'Springfield', 'state' => 'Unknown', 'zip' => '66735'],
    ['first_name' => 'Patty', 'last_name' => 'Bouvier', 'city' => 'Scottsdale', 'state' => 'Arizona', 'zip' => '85250'],
    ['first_name' => 'Moe', 'last_name' => 'Szyslak', 'city' => 'Scottsdale', 'state' => 'Arizona', 'zip' => '85255'],
    ['first_name' => 'Nick', 'last_name' => 'Riviera', 'city' => 'Scottsdale', 'state' => 'Arizona', 'zip' => '85255'],
];

DBクエリでできることと同じようにソートできるようにしたいと思います。ああ、時には列/キーを数値で指定する必要があります。

私が念頭に置いていたのは、これに似たものでした:

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

私が終わらせたいのはこれです:

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
        )

)

更新:理想的には、ソリューションによって動的に作成されると思います

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

問題は、そこにそれらのキー名を「ハードコード」する必要がないことですExample #3 Sorting database results from the array_multisort()documentation that 最終的に使用したものに基づいてソリューションを作成しようとしましたarray_multisort()が、動的に構築された引数リストを に使用する方法が見つからないようですarray_multisort()

私の試みは、これらの引数を配列に「チェーン」してから、

call_user_func_array( 'array_multisort', $functionArgs);

その結果、

警告: array_multisort() のパラメータ 2 は参照であると予想されます。値は次で指定されます...

4

5 に答える 5

4

PHP 5.3 では、配列内のすべてのパラメータを で呼び出すときに参照する必要がありarray_multisort()ますcall_user_func_array()

この関数は、多次元配列をソートし、正しく機能する参照されたパラメーターの配列を作成する方法を示します。

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

例:

$data は、質問から指定された配列です

$sorted_data = msort('city', SORT_ASC, SORT_STRING, 'zip', SORT_DESC, SORT_NUMERIC, $data)
于 2010-05-11T13:26:30.700 に答える
1

これが、多次元配列をソートできるようにするために最終的に落ち着いたものです。上記の答えはどちらも良いですが、柔軟なものも探していました。

「正しい」答えは絶対にないと思いますが、これは私のニーズに合っているものであり、柔軟性があります。

@link私のコメントからわかる_usortByMultipleKeys()ように、現在存在しないように見える PHP マニュアルのコメントから改作されましたが、http://www.php.net/manual/en/function.usort. php#104398は元のコメントの新しいバージョンです。私はその新しい提案を使用して調査していません。

/**
 * 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;
        }
    };
}
于 2011-08-13T00:23:28.260 に答える