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

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个回答

2123

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

function sortByOrder($a, $b) {
    if ($a['order'] > $b['order']) {
        return 1;
    } elseif ($a['order'] < $b['order']) {
        return -1;
    }
    return 0;
}

usort($myArray, 'sortByOrder');
自 PHP 5.3 开始,您可以使用匿名函数:
usort($myArray, function($a, $b) {
    if ($a['order'] > $b['order']) {
        return 1;
    } elseif ($a['order'] < $b['order']) {
        return -1;
    }
    return 0;
});

使用 PHP 7,您可以使用太空船运算符

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

最后,在PHP 7.4中,您可以使用箭头函数来简化代码:

usort($myArray, fn($a, $b) => $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() 函数 - 参见手册中有关数组排序函数的比较

如果您需要回退/决胜排序而不需要任何函数调用来准备值,则在单个太空船运算符的两侧声明规则数组。1 2 如果后续排序规则包含功能开销,则在后续太空船运算符比较之间使用 ?:(三元运算符)。3,以便不必要地调用任何额外的函数。 - mickmackusa
最后一个例子可以使用 ?: 运算符简化:usort($myArray, fn($a, $b) => $a['order'] <=> $b['order'] ?: $a['suborder'] <=> $b['suborder'] ?: $a['subsuborder'] <=> $b['subsuborder']); - fred727

304
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");

10
这个答案缺少教育性的解释。 - mickmackusa
一个循环,然后是本地排序,再加上另一个循环?肯定不是页面上最优雅或性能最佳的代码片段。 - mickmackusa
需要解释一下。 - Peter Mortensen

298

我使用这个函数:

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

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

它之所以有效,是因为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()可以像这样对多个附加数组进行排序,而不仅仅是一个。

需要进行解释。例如,这个想法/主旨是什么?与其他解决方案相比有哪些权衡?性能特征如何,包括理论和实际示例的性能测量?例如,这个解决方案是否非常慢? - Peter Mortensen

136
为了实现这个目标,我们可以使用 "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
        )
)

2
虽然我喜欢学习太空船运算符,但这似乎是最易理解和直接的答案,具有有用的选项,如SORT_DESC和多个sort_flags选项(https://www.php.net/manual/en/function.array-multisort.php)。 - Eric P
这是首选的,因为它可以用一行代码表达。 - DanimalReks
这种方法的另一个好处是,如果您使用了命名键并使用以下代码 usort($myMdArray, fn($a, $b) => $a['order'] <=> $b['order']); ,数组顶层的键名将被移除并替换为索引。这种方法保留了键名。 - undefined
我喜欢这种简单的排序方法,用于降序排列数组。 - undefined
一行代码:array_multisort(array_column($new, 'order'), SORT_ASC, $new); - undefined

86

我通常使用usort,并传递自己的比较函数。在这种情况下,非常简单:

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

在PHP 7中使用太空船运算符:

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

1
它可以工作,那DESC呢? - Meas
3
对于 DESC 排序,您需要在 <=> 运算符中交换 ab 的位置。请参考此答案 - mickmackusa

27

使用以下代码按"title"键的值对数组进行排序:

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

strcmp用于比较字符串。

uasort()保持数组键名不变。


这个回答忽略了原帖作者的要求。问题是要求根据 order 列排序。不管怎样,太空船操作符(在被接受的回答中演示)执行相同的比较,而不需要进行迭代函数调用。 - mickmackusa

23

使用array_multisort()array_map()

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

print_r($array);

演示


请注意,这种方法会发出一个通知。array_multisort 引用它的第一个参数。 - Kami Yang
@Kami,准备好的演示链接中没有你所声称的证据。我不会使用这个答案,因为array_column()更合适/简洁。 - mickmackusa
这是 ajuchacko91 之前发布的答案的简化版本。 - mickmackusa

19
$sort = array();
$array_lowercase = array_map('strtolower', $array_to_be_sorted);
array_multisort($array_lowercase, SORT_ASC, SORT_STRING, $alphabetically_ordered_array);

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


5
这如何回答关于按特定数组键排序的问题? - Sean H
@Nitro 这个答案缺少教育性的解释。这个答案似乎是针对另一个问题的正确答案。 - mickmackusa

9

如最佳答案所述,您可以使用:

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

如果您需要按多个列进行排序,则应按以下方式操作:
usort($myArray, function($a, $b) {
    return [$a['column1'],$a['column2']] <=> [$b['column1'],$b['column2']];
});

这可以扩展到您数据中的任意列。这依赖于PHP中可以直接比较数组的事实。在上面的示例中,数组首先按column1排序,然后按column2排序。但您可以按任何顺序对列进行排序,例如:

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

如果你需要将一列按升序排列,另一列按降序排列,那么请将降序的列与操作符 <=> 的另一侧进行交换:

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

在 Stack Overflow 的过去 14 年内容生成中,有许多关于多列排序的演示,其中之一是 此处。还有另一个演示 - mickmackusa
而且还有 这个。嗯,越是重新阅读问题和这个答案,似乎这个答案应该发布在另一页上,因为它重复了已接受答案中的建议,然后扩展了问题范围。最好找一个尚未演示如何按多列排序的页面。 - mickmackusa
我想我对我的答案属于哪里持不可知论。你说得对,我回答了比问题要求的更多。人们会发现这个问题或其他问题,所以他们更有可能遇到我们的答案和这种(简单)的排序方式。我们只需要赞! - Guillermo Phillips
@Ben,您认为这个答案中哪一部分在PHP7.4之前不起作用?太空船操作符早在PHP7中就已经可用了。证明:https://3v4l.org/sdhdo - mickmackusa
这仅适用于PHP 7.0及以上版本。(这纠正了我的先前评论,错误地声明为7.4而不是7.0。)@mickmackusa - Ben Shoval

7
最灵活的方法是使用这种方法:
Arr::sortByKeys(array $array, $keys, bool $assoc = true): array

这就是原因:
  • 您可以按任何键进行排序(也可以嵌套,例如'key1.key2.key3'['k1', 'k2', 'k3']

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

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

在您的情况下,这很简单:

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

这个方法是这个库的一部分。

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