2009-05-01 118 views
6

我期望能够对多个列上的多维数组进行排序。为了进一步复杂化,我希望能够为每个键/列设置特定的排序选项。我有什么是类似于数据库查询的结果,但实际上并不是一个来源,因此需要使用PHP而不是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 
     ) 

) 

我希望能够对它进行排序,类似于可以用数据库查询完成的操作。哦,有时一个列/键需要用数字来指定。

我脑子里想的是什么类似于这样:

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

问题是我不想在那里“硬编码”那些关键名称。我试图创建一个基于的解决方案示例#3从array_multisort()文档中排序数据库结果最终使用array_multisort()但我似乎无法找到一种方法来使用我的动态构建的参数列表array_multisort()

我的尝试是“连锁”这些参数组合成一个数组,然后

call_user_func_array('array_multisort', $functionArgs); 

,在一个

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

回答

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

我同意没有一个“正确”的答案,但补充一点,这与我的需求非常接近,除了例外,我需要对索引数组进行排序,而不是关联数组。 – 2014-05-07 11:02:33

1

结果你可能想使用usort尝试。你所要做的就是制作一个函数,告诉分拣机如何对其进行分类。文档有关于如何做到这一点的更多信息。

3

这应该适用于您描述的情况。

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

你可以凝结成一条线,像这样:

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']))); 
} 

至于有一个可定制的排序功能,你重新发明轮子。看看array_multisort()函数。

+0

我不同意重新发明轮子。据我所知,如果我想对数据进行排序,就像数据表一样,按照一列排序,而用另一个排序数据`array_multisort()`不是正确的选择,因为它会对每个数据进行排序阵列独立。我需要他们按照特定的顺序排列,具体的方向,我不知道第一手。 crazyj的解决方案就是这种情况。 – 2014-05-07 11:08:58

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

例子:

$的数据是从问题

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