【问题标题】:How to Sort a Multi-dimensional Array by Value如何按值对多维数组进行排序
【发布时间】:2021-07-11 19:18:36
【问题描述】:

如何按“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
        )
)

【问题讨论】:

标签: php arrays sorting multidimensional-array


【解决方案1】:

试试usort。如果您仍在使用 PHP 5.2 或更早版本,则必须先定义一个排序函数:

function sortByOrder($a, $b) {
    return $a['order'] - $b['order'];
}

usort($myArray, 'sortByOrder');

从 PHP 5.3 开始,您可以使用匿名函数:

usort($myArray, function($a, $b) {
    return $a['order'] - $b['order'];
});

最后在 PHP 7 中你可以使用spaceship operator:

usort($myArray, function($a, $b) {
    return $a['order'] <=> $b['order'];
});

要将其扩展到多维排序,如果第一个排序元素为零,请参考第二个/第三个排序元素 - 最好在下面解释。您也可以使用它对子元素进行排序。

usort($myArray, function($a, $b) {
    $retval = $a['order'] <=> $b['order'];
    if ($retval == 0) {
        $retval = $a['suborder'] <=> $b['suborder'];
        if ($retval == 0) {
            $retval = $a['details']['subsuborder'] <=> $b['details']['subsuborder'];
        }
    }
    return $retval;
});

如果您需要保留键关联,请使用uasort() - 请参阅手册中的comparison of array sorting functions

【讨论】:

  • 如果您需要回退/决胜局排序而不需要任何函数调用来准备值,则在单个宇宙飞船运算符的两侧声明一个规则数组。 1 2 如果后续排序规则包含功能开销,则在后续太空飞船运算符比较之间使用?:(三元运算符)。 3 这样就不会不必要地调用额外的函数。
【解决方案2】:
function aasort (&$array, $key) {
    $sorter = array();
    $ret = array();
    reset($array);
    foreach ($array as $ii => $va) {
        $sorter[$ii] = $va[$key];
    }
    asort($sorter);
    foreach ($sorter as $ii => $va) {
        $ret[$ii] = $array[$ii];
    }
    $array = $ret;
}

aasort($your_array, "order");

【讨论】:

  • 这个答案缺少教育解释。
  • 一个循环,然后是原生排序,然后是另一个循环?当然不是页面上最优雅或性能最好的 sn-p。
  • 解释一下。
【解决方案3】:

我使用这个功能:

function array_sort_by_column(&$arr, $col, $dir = SORT_ASC) {
    $sort_col = array();
    foreach ($arr as $key => $row) {
        $sort_col[$key] = $row[$col];
    }

    array_multisort($sort_col, $dir, $arr);
}

array_sort_by_column($array, 'order');

编辑 这个答案至少有十年的历史了,现在可能有更好的解决方案,但我会根据几个 cmets 的要求添加一些额外的信息。

之所以有效,是因为array_multisort() 可以对多个数组进行排序。示例输入:

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

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

首先创建$sort_col,它是一个二维数组,其值是我们要排序的值,键与输入数组匹配。例如对于这个输入,选择键 $sort_col "order" 我们得到:

Array
(
    [0] => 3,
    [1] => 2
)

array_multisort() 然后对该数组进行排序(产生键顺序1, 0),但这只是二维数组。所以原始输入数组也作为$rest 参数传递。当键匹配时,它将被排序,因此它的键也是相同的顺序,给出所需的结果。

注意:

  • 它是通过引用传递的,因此提供的数组被原地修改。
  • array_multisort() 可以像这样对多个附加数组进行排序,而不仅仅是一个

【讨论】:

  • 这个答案缺少教育解释。
  • 解释一下。例如,想法/要点是什么?与其他解决方案相比有哪些权衡?性能特征是什么,理论和实际示例性能测量?例如,这个解决方案是不是很慢?
【解决方案4】:

为此,我们可以使用“对多维或多维数组进行排序”的“array_multisort”方法。它的方法参数是

  • $keys - 正在排序的数组
  • SORT_ASC - 排序顺序(升序)
  • 排序标志(正常比较项目(不要更改类型) 或数字或字符串)
  • $new - 然后是其余的数组。只有元素 对应于前面的等效元素
    比较数组。

'sort flags' 默认为 SORT_REGULAR,被省略。

$new = [
    [
        'hashtag' => 'a7e87329b5eab8578f4f1098a152d6f4',
        'title' => 'Flower',
        'order' => 3,
    ],
    [
        'hashtag' => 'b24ce0cd392a5b0b8dedc66c25213594',
        'title' => 'Free',
        'order' => 2,
    ],
    [
        'hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
        'title' => 'Ready',
        'order' => 1,
    ],
];
$keys = array_column($new, 'order');
array_multisort($keys, SORT_ASC, $new);
var_dump($new);

结果:

Array
(
    [0] => Array
        (
            [hashtag] => e7d31fc0602fb2ede144d18cdffd816b
            [title] => Ready
            [order] => 1
        )
    [1] => Array
        (
            [hashtag] => b24ce0cd392a5b0b8dedc66c25213594
            [title] => Free
            [order] => 2
        )
    [2] => Array
        (
            [hashtag] => a7e87329b5eab8578f4f1098a152d6f4
            [title] => Flower
            [order] => 3
        )
)

【讨论】:

    【解决方案5】:

    我通常使用usort,并通过我自己的比较函数。在这种情况下,就很简单了:

    function compareOrder($a, $b)
    {
      return $a['order'] - $b['order'];
    }
    usort($array, 'compareOrder');
    

    在 PHP 7 中使用 spaceship 运算符:

    usort($array, function($a, $b) {
        return $a['order'] <=> $b['order'];
    });
    

    【讨论】:

    • 谢谢 DESC 怎么样?
    【解决方案6】:

    要按“title”键的值对数组进行排序,请使用:

    uasort($myArray, function($a, $b) {
        return strcmp($a['title'], $b['title']);
    });
    

    strcmp比较字符串。

    uasort() 按照定义的方式维护数组键。

    【讨论】:

    • 这个答案忽略了 OP 的要求。该问题询问如何对order 列进行排序。无论如何,宇宙飞船运算符(在接受的答案中演示)执行相同的比较而不进行迭代函数调用。
    【解决方案7】:

    使用array_multisort()array_map()

    array_multisort(array_map(function($element) {
          return $element['order'];
      }, $array), SORT_ASC, $array);
    
    print_r($array);
    

    DEMO

    【讨论】:

    • 请注意,这种方法会发出通知。 array_multisort 引用它的第一个参数。
    • @Kami 在现成的演示链接中没有您声称的证据。我不会使用这个答案,因为array_column() 更合适/更简洁。
    • 这是 ajuchacko91 较早发布的答案的不太完善的版本。
    【解决方案8】:
    $sort = array();
    $array_lowercase = array_map('strtolower', $array_to_be_sorted);
    array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);
    

    这会处理大写和小写字母。

    【讨论】:

    • 这如何回答按特定数组键排序的问题?
    • @Nitro 这个答案缺少教育解释。这个答案似乎是另一个问题的正确答案。
    【解决方案9】:

    最灵活的方法是使用这种方法:

    Arr::sortByKeys(array $array, $keys, bool $assoc = true): array
    

    原因如下:

    • 您可以按任意键排序(也可以嵌套,如 'key1.key2.key3'['k1', 'k2', 'k3']

    • 它适用于关联数组和非关联数组($assoc 标志)

    • 它不使用引用 - 它返回一个新的排序数组

    在你的情况下,它会很简单:

    $sortedArray = Arr::sortByKeys($array, 'order');
    

    这个方法是this library的一部分。

    【讨论】:

      【解决方案10】:

      去做吧,适用于 7.4 及更高版本

      uasort($yourArray,fn($prev,$now)=>$prev['order']<=>$now['order']);
      
      

      漂亮的打印

      echo '<pre>';
      print_r($yourArray);
      

      【讨论】:

        【解决方案11】:

        如果有人需要根据键排序,最好使用以下:

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

        【讨论】:

        【解决方案12】:

        此解决方案适用于 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
          ;
        });
        

        【讨论】:

        【解决方案13】:

        您可以使用usort 和带有回调函数的用户定义排序函数:

        usort($new, fn($a, $b) => $a['order'] - $b['order']);
        

        技巧:您可以使用a &gt; ba - ba &lt;=&gt; b升序 顺序进行排序。对于降序,只需将ab 的交换位置。

        【讨论】:

        • 所有这些选项都会产生稳定的排序吗?
        【解决方案14】:

        我觉得这很有帮助:

            $columns = array_column($data, "order");
            array_multisort($columns, SORT_ASC, $data);
        

        Sort by name ascending

        【讨论】:

          【解决方案15】:

          让我们面对现实吧: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);
              }
          }
          

          【讨论】:

          • “让我们面对现实吧:php 没有一个简单的开箱即用的函数来正确处理每个数组排序方案。”这正是 usort/ksort/asort 为 ^^' 设计的
          • 其实 PHP a lot of sorting functions 可以用来处理所有的数组排序场景。
          • 关于调试和维护,global的使用是一个巨大的红旗,是generally discouraged。为什么mysql_fetch_array 是针对这个问题而不是 OP 的源数组来演示的,并且没有解释您的代码在做什么以及人们可以期待结果是什么?总体而言,这是一种非常复杂的方法来实现预期的最终结果。
          • @tonygil 我无法从您的答案和 OP 的数据集中确定您的预期结果。这对您来说可能很明显,但我不知道您的回答如何回答 OP 的问题。但是,您可以使用pass by-reference 而不是使用global,请参阅:3v4l.org/FEeFC 这会生成一个明确定义的变量,而不是可以全局更改和访问的变量。
          • 这个答案与原来的问题相差太大。如果这个 sn-p 与问题的样本数据不相似,研究人员如何将此解决方案与其他答案进行比较并得出最喜欢的答案?
          猜你喜欢
          • 2011-03-17
          • 1970-01-01
          • 2012-06-15
          • 2013-04-03
          相关资源
          最近更新 更多