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

How to sort an array of associative arrays by value of a given key in PHP?

给定此数组:

1
2
3
4
5
6
7
$inventory = array(

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

);

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

1
2
3
4
5
6
7
$inventory = array(

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

);

我该怎么做?


你说得对,你要找的功能是array_multisort()

下面是一个直接从手册中选取的示例,并根据您的情况进行了调整:

1
2
3
4
5
6
$price = array();
foreach ($inventory as $key => $row)
{
    $price[$key] = $row['price'];
}
array_multisort($price, SORT_DESC, $inventory);

0

1
2
3
$price = array_column($inventory, 'price');

array_multisort($price, SORT_DESC, $inventory);


PHP 7 +

从php 7开始,可以使用usort和一个匿名函数(使用spaceship操作符比较元素)简洁地完成这项工作。

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

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

或者像这样的降序排序:

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

要了解这是如何工作的,请注意,usort采用用户提供的比较函数,该函数的行为必须如下(从文档中):

The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.

还要注意的是,宇宙飞船操作员<=>

returns 0 if both operands are equal, 1 if the left is greater, and -1 if the right is greater

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

makes writing ordering callbacks for use with usort() easier

PHP 5.3 +

php 5.3引入了匿名函数,但还没有spaceship操作符。我们仍然可以使用usort对数组进行排序,但这有点冗长,更难理解:

1
2
3
4
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正常工作:

Returning non-integer values from the comparison function, such as float, will result in an internal cast to integer of the callback's return value. So values such as 0.99 and 0.1 will both be cast to an integer value of 0, which will compare such values as equal.

在php 5.x中使用usort时,这是需要记住的一个重要陷阱!我最初的回答犯了这个错误,但是我在数千个观点上累积了10票赞成票,显然没有人注意到严重的错误。像我这样的lackwits很容易搞砸comparator函数,这正是php 7语言中添加了易于使用的spaceship操作符的原因。


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

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


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

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

生成以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

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

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

)


我就这样结束了:

1
2
3
4
5
6
7
8
9
10
function sort_array_of_array(&$array, $subfield)
{
    $sortarray = array();
    foreach ($array as $key => $row)
    {
        $sortarray[$key] = $row[$subfield];
    }

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

只需调用函数,传递数组和第二级数组的字段名。像:

1
sort_array_of_array($inventory, 'price');


您可以使用带匿名功能的usort,例如

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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$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']."

"
);
// 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']."
"
);
}

输出:

2


根据php中给定键的值对关联数组进行排序:

uasort(http://php.net/uasort)允许您根据自己定义的函数对数组进行排序。在您的例子中,这很简单:

1
2
3
4
5
6
7
8
9
10
11
$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'];
}

uasort($array,"cmp");


在10万份记录中进行了测试:以秒为单位的时间(由funciton microtime计算)。仅用于排序关键位置时的唯一值。

@josh davis的功能解决方案:花费时间:1.5768740177155

矿山解决方案:花费时间:0.094044923782349

解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
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*
}


此功能可重复使用:

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

默认情况下,它在字符串值上工作得很好,但是如果您的所有值都是数字,则必须为数字比较函数的回调子函数。


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


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//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
    )

)

这是我很久以前发现的一种清理方法。这非常有效,并且可以快速更改以接受对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * 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');


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$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;


}


完全动态功能我跳到这里进行关联数组排序,在http://php.net/manual/en/function.sort.php上发现了这个惊人的函数。这个函数是非常动态的,用指定的键按升序和降序排序。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  <?php

$inventory = array(

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

);



function myfunc($a,$b){
return strnatcmp($a['price'],$b['price']);
}
$result=usort ($inventory,"myfunc");?>
[cc lang="php"]<?php print_r(array_reverse($inventory)); ?>

< /代码>

简单的解决方案:)

输出是

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Array
(
    [0] => Array
        (
            [type] => pork
            [price] => 5.43
        )

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

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

)


试试这个:

1
asort($array_to_sort, SORT_NUMERIC);

参考如下:http://php.net/manual/en/function.asort.php

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