ChatGPT解决这个技术问题 Extra ChatGPT

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

给定这个数组:

$inventory = array(

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

);

我想按价格对 $inventory 的元素进行排序以获得:

$inventory = array(

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

);

我怎样才能做到这一点?

为什么不简单地重组您的输入数组,使 price 列在前,type 列在后?这样,您只需调用 rsort()3v4l.org/2meqs

A
AbraCadaver

没错,您要查找的函数是 array_multisort()

这是直接取自手册并适用于您的案例的示例:

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

从 PHP 5.5.0 开始,您可以使用 array_column() 代替 foreach:

$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);

虽然这肯定比替代品更贵。
更贵?这很奇怪,在我的机器上(运行 PHP 5.3.1-dev)array_multisort() 在小数组上快了几个百分点,在大数组上快了 100 倍(超过 100 个元素)
使用数字键不需要任何更改。如果您遇到与数字键相关的错误或奇怪行为,请将其作为新问题发布。
array_multisort 有一个大问题:它不维护原始键。
@machineaddict 它确实维护关联键。
C
Community

PHP 7+

从 PHP 7 开始,这可以通过使用 usort 和使用 spaceship operator 比较元素的 anonymous function 来简洁地完成。

您可以像这样进行升序排序:

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

或者像这样的降序排序:

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

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

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

另请注意,宇宙飞船运算符 <=>

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

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

使编写用于 usort() 的排序回调更容易

PHP 5.3+

PHP 5.3 引入了匿名函数,但还没有 spaceship 运算符。我们仍然可以使用 usort 对数组进行排序,但它有点冗长且难以理解:

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

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

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

这是在 PHP 5.x 中使用 usort 时要牢记的一个重要陷阱! My original version of this answer 犯了这个错误,但我显然在没有人注意到这个严重错误的情况下,在数千次观看中获得了 10 次赞成票。 正是,像我这样的笨蛋可以轻松搞砸比较器函数,这正是 PHP 7 中将更易于使用的 spaceship 运算符添加到语言中的原因。


抱歉,这种方法会从关联数组中删除字符串键。应该使用“uasort”函数。
@DotMat 有趣 - 我不知道 uasort。但是,在查看文档后,这个答案仍然是正确的在这种情况下。在 OP 的示例中,要排序的数组具有顺序数字索引而不是字符串索引,因此 usort 更合适。在按顺序索引的数组上使用 uasort 将导致排序后的数组不按其数字索引排序,因此在 foreach 循环中看到的第一个元素不是 $your_array[0],这不太可能是理想的行为.
P
Pradeep Kumar

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

array_multisort(array_column($inventory, 'price'), SORT_DESC, $inventory);

如果您想对字符串进行不区分大小写排序,可以使用 SORT_NATURAL|SORT_FLAG_CASE

array_multisort(array_column($inventory, 'key_name'), SORT_DESC, SORT_NATURAL|SORT_FLAG_CASE, $inventory);

由于某种原因,我无法使其与具有小写/大写字母的字符串一起使用。即使使用 SORT_FLAG_CASE。以下对我来说适用于字符串比较:array_multisort(array_map(strtolower, array_column($ipr_projects, 'Name')), SORT_ASC, $ipr_projects);
运行良好 PHP 7.4
z
zombat

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

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

产生以下内容:

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

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

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

)

结合此处的其他一些评论(uasort 和内联匿名函数),您将得到以下单行:uasort( $inventory, function ($a, $b) { if ( $a==$b ) return 0; else return ($a > $b) ? -1 : 1; });
@AlanPorter usort 似乎比 uasort 更适合使用顺序数字键对数组进行排序。以第一个元素位于索引 1 而第二个元素位于索引 0 的数组结尾是一种奇怪的行为,对于不熟悉 PHP 数组细节的人来说无疑是一个陷阱; usort 为您提供直观期望的输出。
z
zkanoca

我结束了这个:

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

    array_multisort($sortarray, SORT_ASC, $array);
}

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

sort_array_of_array($inventory, 'price');

@MarkAmery 我更喜欢函数中包含的答案。它鼓励复制粘贴使用函数,并希望编写更少的意大利面条代码。
k
kenorb

您可以将 usort 与匿名函数一起使用,例如

usort($inventory, function ($a, $b) { return strnatcmp($a['price'], $b['price']); });

版本 PHP 5 >= 5.5.0, PHP 7 适合像我这样真正希望它为他们工作的人..
值得注意的是,用于比较字符串的 strnatcmp 在这里似乎可以正常工作。显然,它实现的“自然顺序”包括按数字而不是按词汇对数字字符串进行排序。
K
Kamal

Sort an array of associative arrays by value of given key in 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);

输出:

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

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

    [2] => Array
        (
            [price] => 8800.50
            [product] => test2
        )
  )

这个答案出现在低质量审查队列中,大概是因为您没有提供任何代码解释。如果此代码回答了问题,请考虑在答案中添加一些解释代码的文本。这样一来,您就更有可能获得更多支持——并帮助提问者学习新知识。
-1;这里的 cmp 函数是错误的。它应该返回 “如果第一个参数被认为分别小于、等于或大于第二个参数,则它是一个小于、等于或大于零的整数”,而是返回 {2 } 或 false。值得注意的是,它似乎仍然有效 - 也许是因为 usort 和朋友的当前实现同样对待“小于”和“等于”情况 - 但不要指望它在未来的 PHP 版本中继续工作。如果他们试图使排序稳定(即不要不必要地围绕相等的元素移动),这将中断。
此外,这里的 usortuasort 更合适,因为 uasort 保留了键和值之间的关联,这在处理顺序数字数组时会令人困惑和意外。例如,调用 uasort 后的上述 $array 的索引依次为 2、0 和 1。除非出于某种原因需要,否则使用 usort 可能会更舒服,它会重新索引数组并对其重新排序。
在 php7+ 中:在 cmp 函数中应该使用 <=> 'spaceship' 运算符
d
danamlund
$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");
}

输出:

first: pork

pork: 5.43
fruit: 3.5
milk: 2.9

A
Arda Basoglu

适用于 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;
}

用法:

$inventory = sortAssociativeArrayByKey($inventory, "price", "ASC");

像魅力一样工作。
m
mirado

我像这样使用 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);

仅代码答案在 Stack Overflow 上的价值很低,因为它们在教育/授权 OP 和成千上万的未来研究人员方面做得很差。此外,建议几年前已经提供的技术对研究人员没有帮助——事实上,这会浪费他们的研究时间,因为他们最终会阅读更多内容但没有获得新信息。
N
Nefelim

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

@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*
}

但是,对唯一排序键的要求有点破坏交易。如果您有可以作为键的唯一排序值,这就引出了一个问题:为什么不简单地用这些键构造数组呢?在 OP 的场景中,很难想象两个价格相同的商品是不可能的。请记住,使用此解决方案会导致数组中的项目神秘而无声地从排序的结果集中消失。
@Chris Baker,你是对的。这仅适用于唯一值。但是这个解决方案工作得非常快,所以速度是制造和使用它的原因。目前可能不实际,需要使用 PHP 7.1.x 进行测试。
j
jamshid

尝试这个:

$prices = array_column($inventory, 'price');
array_multisort($prices, SORT_DESC, $inventory);
print_r($inventory);

您好,欢迎来到 stackoverflow,感谢您的回答。虽然这段代码可能会回答这个问题,但您是否可以考虑添加一些解释来说明您解决了什么问题,以及您是如何解决的?这将有助于未来的读者更好地理解您的答案并从中学习。
请永远不要重复以前帖子的建议(尤其是在同一页面上)。这不必要地使 Stack Overflow 膨胀并浪费研究人员的时间。
C
Community

此功能可重复使用:

function usortarr(&$array, $key, $callback = 'strnatcasecmp') {
    uasort($array, function($a, $b) use($key, $callback) {
        return call_user_func($callback, $a[$key], $b[$key]);
    });
}

默认情况下,它适用于字符串值,但如果您的所有值都是数字,则必须将回调子用于 number comparison function


您调用此 usortarr,但随后调用 uasort 而不是 usort;也许有点混乱。后者是 - 在具有数字索引的顺序数组的情况下,就像问题中展示的那样 - 可能是您真正想要的。
A
Alex Sexton

您可以尝试定义自己的比较函数,然后使用 usort


是的。如果我找不到解决方案,我会这样做。我很确定有一些奇怪的参数可以添加到其中一种来实现这一点。不过谢谢你的想法!
与此处发布的其他答案相比,此答案看起来更像是一个“提示”,应该是问题下的评论而不是答案。
k
kray

这是我很久以前发现并清理了一下的方法。这很好用,并且可以快速更改以接受对象。

/**
 * A method for sorting arrays by a certain key:value.
 * SortByKey is the key you wish to sort by
 * Direction can be ASC or DESC.
 *
 * @param $array
 * @param $sortByKey
 * @param $sortDirection
 * @return array
 */
private function sortArray($array, $sortByKey, $sortDirection) {

    $sortArray = array();
    $tempArray = array();

    foreach ( $array as $key => $value ) {
        $tempArray[] = strtolower( $value[ $sortByKey ] );
    }

    if($sortDirection=='ASC'){ asort($tempArray ); }
        else{ arsort($tempArray ); }

    foreach ( $tempArray as $key => $temp ){
        $sortArray[] = $array[ $key ];
    }

    return $sortArray;

}

要更改对对象进行排序的方法,只需更改以下行:

$tempArray[] = strtolower( $value[ $sortByKey ] );$tempArray[] = strtolower( $value->$sortByKey );

要运行该方法,只需执行

sortArray($inventory,'price','ASC');


这种方法有效,但比 Josh Davis 的答案(使用 array_multisort)或我的答案(使用 usort)要简洁一些,并且似乎没有比它们提供任何优势作为交换。
K
Kamal
//Just in one line custom function
function cmp($a, $b)
{
return (float) $a['price'] < (float)$b['price'];
}
@uasort($inventory, "cmp");
print_r($inventory);

//result

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

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

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

)

m
mickmackusa

自 PHP 7.4 起,您可以使用箭头函数:

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

代码 (demo):

$inventory = [
    ['type' => 'fruit', 'price' => 3.50],
    ['type' => 'milk',  'price' => 2.90],
    ['type' => 'pork',  'price' => 5.43],
];

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

print_r($inventory);

(浓缩)输出:

Array
(
    [0] => Array ([type] => pork,  [price] => 5.43)
    [1] => Array ([type] => fruit, [price] => 3.5)
    [2] => Array ([type] => milk,  [price] => 2.9)
)

A
Ahmad Sayeed

完整的动态函数我跳到这里进行关联数组排序,并在 http://php.net/manual/en/function.sort.php 上发现了这个神奇的函数。此功能非常动态,可以使用指定的键进行升序和降序排序。

按特定键对数组进行排序的简单函数。维护索引关联

<?php

function array_sort($array, $on, $order=SORT_ASC)
{
    $new_array = array();
    $sortable_array = array();

    if (count($array) > 0) {
        foreach ($array as $k => $v) {
            if (is_array($v)) {
                foreach ($v as $k2 => $v2) {
                    if ($k2 == $on) {
                        $sortable_array[$k] = $v2;
                    }
                }
            } else {
                $sortable_array[$k] = $v;
            }
        }

        switch ($order) {
            case SORT_ASC:
                asort($sortable_array);
            break;
            case SORT_DESC:
                arsort($sortable_array);
            break;
        }

        foreach ($sortable_array as $k => $v) {
            $new_array[$k] = $array[$k];
        }
    }

    return $new_array;
}

$people = array(
    12345 => array(
        'id' => 12345,
        'first_name' => 'Joe',
        'surname' => 'Bloggs',
        'age' => 23,
        'sex' => 'm'
    ),
    12346 => array(
        'id' => 12346,
        'first_name' => 'Adam',
        'surname' => 'Smith',
        'age' => 18,
        'sex' => 'm'
    ),
    12347 => array(
        'id' => 12347,
        'first_name' => 'Amy',
        'surname' => 'Jones',
        'age' => 21,
        'sex' => 'f'
    )
);

print_r(array_sort($people, 'age', SORT_DESC)); // Sort by oldest first
print_r(array_sort($people, 'surname', SORT_ASC)); // Sort by surname

J
Jason Campbell

如果您需要对具有不同大小写的字符串数组进行排序,这会将排序数组值更改为小写。

$data = [
    [
        'name' => 'jack',
        'eyeColor' => 'green'
    ],
    [
        'name' => 'Amy',
        'eyeColor' => 'brown'
    ],
    [   
        'name' => 'Cody',
        'eyeColor' => 'blue'
    ] 
];
function toLowerCase($a) { return strtolower($a); }
$sortArray = array_map("toLowerCase",array_column($data, 'name'));
array_multisort($sortArray, SORT_ASC, $data);

E
Ejaz UL Haq

此功能在所有主要版本的 PHP 上 100% 工作,并且已使用 PHP5、PHP7、PHP8 进行了测试。

    function sort_my_array($array, $order_by, $order)
    {
        switch ($order) {
            case "asc":
                usort($array, function ($first, $second) use ($order_by) {
                    if (version_compare(PHP_VERSION, '7.0.0') >= 0) {
                        return $first[$order_by] <=> $second[$order_by];
                    } else {
                        $array_cmp = strcmp($first[$order_by], $second[$order_by]);
                        return $array_cmp ;
                    }
                });
                break;
            case "desc":
                usort($certificates, function ($first, $second) use ($order_by) {
                    if (version_compare(PHP_VERSION, '7.0.0') >= 0) {
                        return $first[$order_by] <=> $second[$order_by];
                    } else {
                        $array_cmp = strcmp($first[$order_by], $second[$order_by]);
                        return -$array_cmp ;
                    }
                });
                break;
            default:
                break;
        }
        return $array;
    }

A
Abir Husain

许多人正在寻找一种方法来使用 Laravel 做到这一点并最终来到这里。此外,由于这个问题的重复,一些 Laravel 问题正在关闭。因此,我分享了一种使用 Laravel collect() 方法执行它的简单方法。

$inventory = collect($inventory)->sortBy('price')->toArray();

对于降序

$inventory = collect($inventory)->sortBy('price')->reverse()->toArray();

或者,

$inventory = collect($inventory)->('price')->reverse()->toArray();

z
zkanoca
$arr1 = array(

    array('id'=>1,'name'=>'aA','cat'=>'cc'),
    array('id'=>2,'name'=>'aa','cat'=>'dd'),
    array('id'=>3,'name'=>'bb','cat'=>'cc'),
    array('id'=>4,'name'=>'bb','cat'=>'dd')
);

$result1 = array_msort($arr1, array('name'=>SORT_DESC);

$result2 = array_msort($arr1, array('cat'=>SORT_ASC);

$result3 = array_msort($arr1, array('name'=>SORT_DESC, 'cat'=>SORT_ASC));


function array_msort($array, $cols)
{
    $colarr = array();
    foreach ($cols as $col => $order) {
    $colarr[$col] = array();
    foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}

$eval = 'array_multisort(';

foreach ($cols as $col => $order) {
    $eval .= '$colarr[\''.$col.'\'],'.$order.',';
}

$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
    foreach ($arr as $k => $v) {
        $k = substr($k,1);
        if (!isset($ret[$k])) $ret[$k] = $array[$k];
        $ret[$k][$col] = $array[$k][$col];
    }
}
return $ret;


} 

虽然此代码段可能会解决问题,但 including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。也请尽量不要用解释性注释来拥挤你的代码,因为这会降低代码和解释的可读性!
z
zkanoca

尝试这个:

asort($array_to_sort, SORT_NUMERIC);

供参考,请参阅:http://php.net/manual/en/function.asort.php

在此处查看各种排序标志:http://www.php.net/manual/en/function.sort.php


这不适用于多维数组,但只是帮我解决了另一个问题,谢谢:)
这不能用于按特定字典键对字典列表进行排序,因此不能回答提出的问题。