如何按值对多维数组进行排序

1390

如何按照“order”键的值对这个数组进行排序?

尽管当前的值是连续的,但它们并不总是连续的。

Array
(
    [0] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )

    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )

    [2] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
)

最快的方法是使用同构的 sort-array 模块,它可以在浏览器和 Node 中本地运行,支持任何类型的输入、计算字段和自定义排序顺序。 - Lloyd
一行代码 array_multisort(array_column($array, 'order'), SORT_ASC, $array); - undefined
17个回答

7

在 PHP 7.4 及以上版本中,可以使用“箭头函数”语法:

uasort($yourArray, fn($a, $b) => $a['order'] <=> $b['order']);


漂亮打印。
echo '<pre>';
print_r($yourArray);

1
反转顺序有多难?函数能改变吗,还是需要调用 array_reverse 函数? - Shivanand Sharma
微小的细节是它被称为飞船运算符 - theking2
uasort($yourArray, fn($a, $b) => -1*($a['order'] <=> $b['order'])); 反转... - dılo sürücü
不要用 -1 进行乘法运算,这会让你的代码变得臭味相投。只需要反转 $a$b 的顺序即可:$b['order'] <=> $a['order']这个答案对此进行了解释。 - mickmackusa
不要乘以-1。这会让你的代码变得臭味相投。只需颠倒$a$b的顺序。$b['order'] <=> $a['order']这个答案有解释。 - undefined

3

如果任何人需要按照关键词排序,最好使用以下方式:

usort($array, build_sorter('order'));

function build_sorter($key) {
   return function ($a, $b) use ($key) {
      return strnatcmp($a[$key], $b[$key]);
   };
}

1
基于https://www.php.net/manual/en/function.usort.php中的示例4 - dWinder

2
这个解决方案适用于usort()函数,使用易于记忆的符号来进行多维排序。此处使用了太空船操作符<=>,该符号在PHP 7及以上版本可用。
usort($in,function($a,$b){
  return $a['first']   <=> $b['first']  //first asc
      ?: $a['second']  <=> $b['second'] //second asc
      ?: $b['third']   <=> $a['third']  //third desc (a b swapped!)
      //etc
  ;
});

示例:

$in = [
  ['firstname' => 'Anton', 'surname' => 'Gruber', 'birthdate' => '03.08.1967', 'rank' => 3],
  ['firstname' => 'Anna', 'surname' => 'Egger', 'birthdate' => '04.01.1960', 'rank' => 1],
  ['firstname' => 'Paul', 'surname' => 'Mueller', 'birthdate' => '15.10.1971', 'rank' => 2],
  ['firstname' => 'Marie', 'surname' => 'Schmidt ', 'birthdate' => '24.12.1963', 'rank' => 2],
  ['firstname' => 'Emma', 'surname' => 'Mueller', 'birthdate' => '23.11.1969', 'rank' => 2],
];

第一个任务:按级别升序、姓氏升序排序

usort($in,function($a,$b){
  return $a['rank']      <=> $b['rank']     //first asc
      ?: $a['surname']   <=> $b['surname']  //second asc
  ;
});

第二任务:按照排名降序、姓氏升序、名字升序排序。
usort($in,function($a,$b){
  return $b['rank']      <=> $a['rank']       //first desc
      ?: $a['surname']   <=> $b['surname']    //second asc
      ?: $a['firstname'] <=> $b['firstname']  //third asc
  ;
});

第三个任务:按照等级降序和出生日期升序排序

这种格式无法对日期进行排序。需要使用strtotime进行转换。

usort($in,function($a,$b){
  return $b['rank']      <=> $a['rank']       //first desc
      ?: strtotime($a['birthdate']) <=> strtotime($b['birthdate'])    //second asc
  ;
});

这个问题只对一个列进行排序。您的答案更适用于此页面: https://dev59.com/MnA75IYBdhLWcg3wi5wr 和 https://dev59.com/9Ww05IYBdhLWcg3wnjLC - mickmackusa

2
您可以使用 usort 和一个带有回调函数的用户定义排序函数:
usort($new, fn($a, $b) => $a['order'] - $b['order']);

技巧: 你可以使用a > ba - ba <=> b 来进行升序排序。对于降序排序,只需交换ab的位置即可。


1
所有这些选项都会导致稳定排序吗? - Peter Mortensen
如果使用箭头函数(PHP7.4或更高版本),那么没有任何借口可以避免使用太空船操作符(PHP7或更高版本)。在我看来,减法会让代码变得臭味相投,并且对于非数字数据也不理想。 - mickmackusa

0
 example  with class:
 
 class user
 {
     private $key;

     public function __construct(string $key)
     {
         $this->key = $key;
     }

     public function __invoke($a, $b)
     {
         return $a[$this->key] <=> $b[$this->key];
     }
 }

 $user = [
     ['id' => 1, 'name' => 'Oliver', 'id_card' => 4444],
     ['id' => 3, 'name' => 'Jack', 'id_card' => 5555],
     ['id' => 2, 'name' => 'Harry', 'id_card' => 6666]
 ];

 // sort user by id
 usort($user, new user('id'));
 var_dump($user);

0

基于相同逻辑的另一个函数:

function array_multisort(&$a, array $column_names) {
    usort($a, function($a, $b) use($column_names) {
        foreach ($column_names as $column_name => $order) {
            $result = ($a[$column_name] <=> $b[$column_name]) * ($order === SORT_DESC ? -1 : 1);
            if ($result) return $result;
        }
        return 0;
    });
}


$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);


var_dump($data);
array_multisort($data, ['volume' => SORT_ASC, 'edition' => SORT_DESC]);
var_dump($data);

-2

让我们面对现实:PHP没有一个简单的开箱即用函数来正确处理每个数组排序场景。

这个例程是直观的,这意味着更快的调试和维护:

// Automatic population of the array
$tempArray = array();
$annotations = array();
// ... some code
// SQL $sql retrieves result array $result
// $row[0] is the ID, but is populated out of order (comes from
// multiple selects populating various dimensions for the same DATE
// for example
while($row = mysql_fetch_array($result)) {
    $needle = $row[0];
    arrayIndexes($needle);  // Create a parallel array with IDs only
    $annotations[$needle]['someDimension'] = $row[1]; // Whatever
}
asort($tempArray);
foreach ($tempArray as $arrayKey) {
    $dataInOrder = $annotations[$arrayKey]['someDimension'];
    // .... more code
}

function arrayIndexes ($needle) {
    global $tempArray;
    if (!in_array($needle, $tempArray)) {
        array_push($tempArray, $needle);
    }
}

6
面对现实吧:PHP没有一个简单的开箱即用的函数来正确地处理每种数组排序场景。这正是usort/ksort/asort设计的目的^^' - benftwc
6
实际上,PHP拥有许多排序函数(http://php.net/manual/en/array.sorting.php),可以用于处理各种数组排序场景。 - axiac
1
关于调试和维护,使用global是一个巨大的警示标志,并且通常会受到反对。为什么在这个问题中演示了mysql_fetch_array而不是OP的源数组,并且没有解释代码正在做什么以及可以期望的结果是什么?总体而言,这是一种实现所需的最终结果非常复杂的方法。 - Will B.
1
@tonygil 我无法确定你对问题的回答和 OP 的数据集有什么期望结果。这可能对你来说很明显,但我不知道你的回答如何回答 OP 的问题。然而,你可以使用按引用传递而不是使用 global,请参见:https://3v4l.org/FEeFC 这将产生一个明确定义的变量,而不是一个可以在全局范围内更改和访问的变量。 - Will B.
1
这个答案与原问题相差太远了。如果这段代码片段与问题的样本数据不相似,研究人员如何将此解决方案与其他答案进行比较并得出喜爱的答案呢? - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接