如何按PHP中给定键的值对关联数组进行排序?

Mat*_*att 402 php arrays sorting multidimensional-array

给定这个数组:

$inventory = array(

   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),
   array("type"=>"pork", "price"=>5.43),

);
Run Code Online (Sandbox Code Playgroud)

我想按价格排序$inventory元素得到:

$inventory = array(

   array("type"=>"pork", "price"=>5.43),
   array("type"=>"fruit", "price"=>3.50),
   array("type"=>"milk", "price"=>2.90),

);
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?

Jos*_*vis 545

你是对的,你正在寻找的功能是array_multisort().

以下是直接从手册中获取并根据您的情况调整的示例:

$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);
Run Code Online (Sandbox Code Playgroud)

  • 虽然这肯定比替代品贵. (5认同)
  • 更贵?这很奇怪,在我的机器上(运行PHP 5.3.1-dev),array_multisort()在小型阵列上快几个百分点,在大型阵列上快100倍(100多个元素) (4认同)
  • 使用数字键不应该进行任何更改.如果您遇到与数字键相关的错误或奇怪的行为,请将其作为新问题发布. (3认同)
  • array_multisort有一个很大的问题:它不维护原始密钥. (3认同)
  • @machineaddict 它确实维护关联键。 (2认同)
  • @MatejSvajger:引用[php.net](http://php.net/manual/en/function.array-multisort.php)`关联(字符串)键将被保留,但数字键将被重新索引。` (2认同)

Mar*_*ery 274

PHP 7+

从PHP 7开始,这可以使用匿名函数简洁地完成usort,该函数使用太空船运算符来比较元素.

你可以这样做一个升序排序:

usort($inventory, function ($item1, $item2) {
    return $item1['price'] <=> $item2['price'];
});
Run Code Online (Sandbox Code Playgroud)

或者是这样的降序:

usort($inventory, function ($item1, $item2) {
    return $item2['price'] <=> $item1['price'];
});
Run Code Online (Sandbox Code Playgroud)

要了解其工作原理,请注意usort采用用户提供的比较函数,该函数的行为必须如下(来自文档):

如果第一个参数被认为分别小于,等于或大于第二个参数,则比较函数必须返回小于,等于或大于零的整数.

还要注意<=>,宇宙飞船运营商,

如果两个操作数相等则返回0,如果左边更大则返回1,如果右边更大则返回-1

这正是usort需要的.事实上,<=>https://wiki.php.net/rfc/combined-comparison-operator中添加语言的几乎所有理由都是它

使编写顺序回调usort()更容易使用


PHP 5.3+

PHP 5.3引入了匿名函数,但还没有太空船运营商.我们仍然可以使用usort对数组进行排序,但它更冗长,更难理解:

usort($inventory, function ($item1, $item2) {
    if ($item1['price'] == $item2['price']) return 0;
    return $item1['price'] < $item2['price'] ? -1 : 1;
});
Run Code Online (Sandbox Code Playgroud)

请注意,虽然处理整数值的比较器只返回值的差异是相当常见的,但在这种情况下$item2['price'] - $item1['price']我们不能安全地做到这一点.这是因为价格是问题提供者示例中的浮点数,但我们传递给的比较函数usort必须返回整数usort才能正常工作:

从比较函数返回非整数值(例如float)将导致内部强制转换为回调返回值的整数.因此,诸如0.99和0.1之类的值都将被转换为0的整数值,这将将这些值比较为相等.

usort在PHP 5.x中使用时,这是一个要记住的重要陷阱!我的这个答案的原始版本犯了这个错误,但我在成千上万的观点中累积了10个赞成票,显然没有人注意到这个严重的错误.像我这样的缺乏人员可以轻松搞砸比较器功能正是因为在PHP 7中将易于使用的太空船操作员添加到语言中.

  • 抱歉,这种方法会从关联数组中删除字符串键.相反,应该使用"uasort"函数. (7认同)
  • @DotMat有趣 - 我不知道[`uasort`](http://php.net/manual/en/function.uasort.php).但是,在查看文档之后,这个答案仍然是正确的*在这种情况下*.在OP的示例中,要排序的数组具有顺序数字索引而不是字符串索引,因此`usort`更合适.在顺序索引的数组上使用`uasort`将导致排序的数组不按其数字索引排序,这样在`foreach`循环中看到的第一个元素不是`$ your_array [0]`,这不太可能是理想的行为. (7认同)

小智 81

虽然其他人已经正确地建议使用array_multisort(),但由于某些原因,似乎没有答案承认存在array_column(),这可以大大简化解决方案.所以我的建议是:

array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);
Run Code Online (Sandbox Code Playgroud)

  • 这是最优雅的答案.应该评分更高! (7认同)
  • 出于某种原因,我无法使其与具有小写/大写字母的字符串一起使用。即使使用 SORT_FLAG_CASE。以下为我的字符串比较工作: array_multisort( array_map(strtolower, array_column($ipr_projects, 'Name')), SORT_ASC, $ipr_projects); (3认同)
  • 最短和最简单的一种,我认为可以接受 (2认同)

zom*_*bat 41

由于数组元素本身是带有字符串键的数组,因此最好的办法是定义自定义比较函数.它非常快速和容易.试试这个:

function invenDescSort($item1,$item2)
{
    if ($item1['price'] == $item2['price']) return 0;
    return ($item1['price'] < $item2['price']) ? 1 : -1;
}
usort($inventory,'invenDescSort');
print_r($inventory);
Run Code Online (Sandbox Code Playgroud)

产生以下内容:

Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

    [1] => Array
        (
            [type] => fruit
            [price] => 3.5
        )

    [2] => Array
        (
            [type] => milk
            [price] => 2.9
        )

)
Run Code Online (Sandbox Code Playgroud)

  • 结合这里的一些其他评论(uasort和内联匿名函数),你得到这个单行:`uasort($ inventory,function($ a,$ b){if($ a == $ b)return 0; else返回($ a> $ b)? - 1:1;});` (3认同)

Dan*_*lzt 24

我结束了这个:

function sort_array_of_array(&$array, $subfield)
{
    $sortarray = array();
    foreach ($array as $key => $row)
    {
        $sortarray[$key] = $row[$subfield];
    }

    array_multisort($sortarray, SORT_ASC, $array);
}
Run Code Online (Sandbox Code Playgroud)

只需调用该函数,传递数组和第二级数组的字段名称.喜欢:

sort_array_of_array($inventory, 'price');
Run Code Online (Sandbox Code Playgroud)

  • @MarkAmery 我更喜欢函数中包含的答案。它鼓励复制粘贴者使用函数,并希望编写更少的意大利面条式代码。 (2认同)

ken*_*orb 17

您可以使用usort匿名函数,例如

usort($inventory, function ($a, $b) { return strnatcmp($a['price'], $b['price']); });
Run Code Online (Sandbox Code Playgroud)


Kam*_*mal 12

From按 php 中给定键的值对关联数组的数组进行排序

通过使用 usort ( http://php.net/usort ),我们可以按升序和降序对数组进行排序。只是我们需要创建一个函数并将其作为参数传递给 usort。根据下面的示例,如果我们传递小于条件,则使用大于升序,然后按降序排序。例子 :

$array = array(
  array('price'=>'1000.50','product'=>'test1'),
  array('price'=>'8800.50','product'=>'test2'),
  array('price'=>'200.0','product'=>'test3')
);

function cmp($a, $b) {
  return $a['price'] > $b['price'];
}

usort($array, "cmp");
print_r($array);
Run Code Online (Sandbox Code Playgroud)

输出:

Array
 (
    [0] => Array
        (
            [price] => 200.0
            [product] => test3
        )

    [1] => Array
        (
            [price] => 1000.50
            [product] => test1
        )

    [2] => Array
        (
            [price] => 8800.50
            [product] => test2
        )
  )
Run Code Online (Sandbox Code Playgroud)


dan*_*und 9

$inventory = 
    array(array("type"=>"fruit", "price"=>3.50),
          array("type"=>"milk", "price"=>2.90),
          array("type"=>"pork", "price"=>5.43),
          );

function pricesort($a, $b) {
  $a = $a['price'];
  $b = $b['price'];
  if ($a == $b)
    return 0;
  return ($a > $b) ? -1 : 1;
}

usort($inventory, "pricesort");
// uksort($inventory, "pricesort");

print("first: ".$inventory[0]['type']."\n\n");
// for usort(): prints milk (item with lowest price)
// for uksort(): prints fruit (item with key 0 in the original $inventory)

// foreach prints the same for usort and uksort.
foreach($inventory as $i){
  print($i['type'].": ".$i['price']."\n");
}
Run Code Online (Sandbox Code Playgroud)

输出:

first: pork

pork: 5.43
fruit: 3.5
milk: 2.9
Run Code Online (Sandbox Code Playgroud)


Sys*_*all 7

从 PHP 7.4 开始,您可以使用箭头函数:

usort(
    $inventory, 
    fn(array $a, array $b): int => $b['price'] <=> $a['price']
);
Run Code Online (Sandbox Code Playgroud)

代码(演示):

usort(
    $inventory, 
    fn(array $a, array $b): int => $b['price'] <=> $a['price']
);
Run Code Online (Sandbox Code Playgroud)

(压缩)输出:

Array
(
    [0] => Array ([type] => pork,  [price] => 5.43)
    [1] => Array ([type] => fruit, [price] => 3.5)
    [2] => Array ([type] => milk,  [price] => 2.9)
)
Run Code Online (Sandbox Code Playgroud)


小智 6

uasort这样用

<?php
$users = [
    [
        'username' => 'joe',
        'age' => 11
    ],
    [
        'username' => 'rakoto',
        'age' => 21
    ],
    [
        'username' => 'rabe',
        'age' => 17
    ],
    [
        'username' => 'fy',
        'age' => 19
    ],    
];


uasort($users, function ($item, $compare) {
    return $item['username'] >= $compare['username']; 
});

var_dump($users);
Run Code Online (Sandbox Code Playgroud)


Nef*_*lim 5

在 100 000 条记录上进行了测试: 以秒为单位的时间(由函数 microtime 计算)。 仅用于排序关键位置的唯一值。

@Josh Davis 的函数解决方案: 花费时间:1.5768740177155

我的解决方案: 花费时间:0.094044923782349

解决方案:

function SortByKeyValue($data, $sortKey, $sort_flags=SORT_ASC)
{
    if (empty($data) or empty($sortKey)) return $data;

    $ordered = array();
    foreach ($data as $key => $value)
        $ordered[$value[$sortKey]] = $value;

    ksort($ordered, $sort_flags);

    return array_values($ordered); *// array_values() added for identical result with multisort*
}
Run Code Online (Sandbox Code Playgroud)

  • 不过,对唯一排序键的要求在某种程度上是一个交易破坏者。如果您有可以作为键的唯一排序值,那就引出了一个问题:为什么不简单地用这些键来构造数组呢?在 OP 的场景中,很难想象价格相同的两件商品是**不可能**的。请记住,使用此解决方案会导致数组中的项目从排序结果集中神秘而无声地消失。 (8认同)

小智 5

尝试这个:

$prices = array_column($inventory, 'price');
array_multisort($prices, SORT_DESC, $inventory);
print_r($inventory);
Run Code Online (Sandbox Code Playgroud)

  • 请不要重复以前帖子的建议(尤其是在同一页面上)。这不必要地使 Stack Overflow 变得臃肿并浪费了研究人员的时间。 (2认同)

Ard*_*glu 5

对于PHP 7及更高版本。

/**
 * A method for sorting associative arrays by a key and a direction.
 * Direction can be ASC or DESC.
 *
 * @param $array
 * @param $key
 * @param $direction
 * @return mixed $array
 */
function sortAssociativeArrayByKey($array, $key, $direction){

    switch ($direction){
        case "ASC":
            usort($array, function ($first, $second) use ($key) {
                return $first[$key] <=> $second[$key];
            });
            break;
        case "DESC":
            usort($array, function ($first, $second) use ($key) {
                return $second[$key] <=> $first[$key];
            });
            break;
        default:
            break;
    }

    return $array;
}
Run Code Online (Sandbox Code Playgroud)

用法:

$inventory = sortAssociativeArrayByKey($inventory, "price", "ASC");
Run Code Online (Sandbox Code Playgroud)