PHP按子数组值排序数组

Posted

技术标签:

【中文标题】PHP按子数组值排序数组【英文标题】:PHP Sort Array By SubArray Value 【发布时间】:2011-01-29 11:13:57 【问题描述】:

我有以下数组结构:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )

根据optionNumber,以增量方式对数组进行排序的最佳方法是什么?

所以结果看起来像:

Array
        (
            [0] => Array
                (
                    [configuration_id] => 8
                    [id] => 1
                    [optionNumber] => 1
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [1] => Array
                (
                    [configuration_id] => 9
                    [id] => 1
                    [optionNumber] => 2
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )

            [2] => Array
                (
                    [configuration_id] => 10
                    [id] => 1
                    [optionNumber] => 3
                    [optionActive] => 1
                    [lastUpdated] => 2010-03-17 15:44:12
                )
    )

【问题讨论】:

【参考方案1】:

使用usort

function cmp_by_optionNumber($a, $b) 
  return $a["optionNumber"] - $b["optionNumber"];


...

usort($array, "cmp_by_optionNumber");

php ≥5.3 中,您应该使用 anonymous function 代替:

usort($array, function ($a, $b) 
    return $a['optionNumber'] - $b['optionNumber'];
);

请注意,上面的两个代码都假定$a['optionNumber'] 是一个整数。如果是字符串,请使用@St. John Johnson's solution。


在 PHP ≥7.0 中,使用spaceship operator <=> 代替减法来防止溢出/截断问题。

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

【讨论】:

这对我没有帮助,因为 usort 需要我提供一个可以使用的功能 - 这是我无法理解的难点 好吧,他只是给了你使用的功能。而且您将不得不接受并不总是有内置函数可以做您想做的事情,您必须自己编写。比较函数只需要返回 1、0 或 -1 来指示两个元素的排序顺序。 我进一步研究了 usort,它实际上很酷。我为上面的那个写了一个简单的比较函数,但是错过了'=='。谢谢大家的帮助 现在也作为闭包:-- usort($array, function($a,$b) return $b["optionNumber"] - $a["optionNumber"]; ); @KiloumapL'artélon 如果结果是&lt; 0,它告诉排序函数a 应该出现在b 之前。如果是&gt; 0,那么b 应该出现在a 之前。【参考方案2】:

使用usort

 usort($array, 'sortByOption');
 function sortByOption($a, $b) 
   return strcmp($a['optionNumber'], $b['optionNumber']);
 

【讨论】:

@BenSinclair,那是因为 Kenny 的解决方案是针对数字的,这个解决方案是针对字符串的。他们都是正确的 :-) 对于这个替代方案 +1。 对于不区分大小写的排序,使用 strcasecmp 而不是 strcmp 我们能否定义数组中二阶的键意味着我们首先使用 optionNumber 进行排序,然后使用 lastUpdated 进行排序。这怎么能行?【参考方案3】:

我使用了KennyTM 和AJ Quick 的两种解决方案,并提出了一个可以在许多情况下帮助解决此问题的功能,例如使用ASC 或DESC 排序或保留键 或者如果您有对象作为数组的子项

这里是这个函数(适用于 PHP7 及更高版本,因为 spaceship 运算符):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)

    if ($preserveKeys) 
        $c = [];
        if (is_object(reset($array))) 
            foreach ($array as $k => $v) 
                $b[$k] = strtolower($v->$value);
            
         else 
            foreach ($array as $k => $v) 
                $b[$k] = strtolower($v[$value]);
            
        
        $asc ? asort($b) : arsort($b);
        foreach ($b as $k => $v) 
            $c[$k] = $array[$k];
        
        $array = $c;
     else 
        if (is_object(reset($array))) 
            usort($array, function ($a, $b) use ($value, $asc) 
                return $a->$value == $b->$value ? 0 : ($a->$value <=> $b->$value) * ($asc ? 1 : -1);
            );
         else 
            usort($array, function ($a, $b) use ($value, $asc) 
                return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
            );
        
    

    return $array;

用法:

sortBySubValue($array, 'optionNumber', true, false);

编辑

第一部分可以用uasort()重写,函数会更短(适用于PHP7及更高版本,因为有spaceship运算符):

/**
 * @param array $array
 * @param string $value
 * @param bool $asc - ASC (true) or DESC (false) sorting
 * @param bool $preserveKeys
 * @return array
 * */
function sortBySubValue($array, $value, $asc = true, $preserveKeys = false)

    if (is_object(reset($array))) 
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) 
            return $a->$value == $b->$value ? 0 : ($a->$value <=> $b->$value) * ($asc ? 1 : -1);
        ) : usort($array, function ($a, $b) use ($value, $asc) 
            return $a->$value == $b->$value ? 0 : ($a->$value <=> $b->$value) * ($asc ? 1 : -1);
        );
     else 
        $preserveKeys ? uasort($array, function ($a, $b) use ($value, $asc) 
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        ) : usort($array, function ($a, $b) use ($value, $asc) 
            return $a[$value] == $b[$value] ? 0 : ($a[$value] <=> $b[$value]) * ($asc ? 1 : -1);
        );
    
    return $array;

【讨论】:

这是这里最好最有用的答案,应该在最上面;) @EdiBudimilic 谢谢你,我很感激!顺便说一句,我已经更新了我的答案并添加了这个函数的更短版本:) 为了使这项工作适合我,在比较 $a$b 值时,我必须使用 &gt;(大于)而不是 -(减号),因为我正在比较字符串。不过仍然有效。 @James 你是对的。我更改了答案并添加了宇宙飞船运算符()的使用。现在它应该可以正常工作了。 有没有办法让这个大小写不敏感?【参考方案4】:

使用array_multisort()、array_map()

array_multisort(array_map(function($element) 
      return $element['optionNumber'];
  , $array), SORT_ASC, $array);

print_r($array);

DEMO

【讨论】:

这很容易工作。谢谢你。我所要做的就是更改我的列名,它就奏效了。 这也保留了父数组的键 我知道这个问题现在有点老了,但我有一个问题:我看到它确实有效,但它是如何工作的?我已经阅读了 php.net 上的 array_multisort 文档,但这对我来说仍然没有多大意义。【参考方案5】:

使用上述功能时会删除键。如果键很重要,下面的函数会维护它……但是 foreach 循环效率很低。

function subval_sort($a,$subkey) 
    foreach($a as $k=>$v) 
        $b[$k] = strtolower($v[$subkey]);
    
    asort($b);
    foreach($b as $key=>$val) 
        $c[$key] = $a[$key];
    
    return $c;

$array = subval_sort($array,'optionNumber');

如果要从高到低,请使用 arsort 而不是 asort。

代码信用:http://www.firsttube.com/read/sorting-a-multi-dimensional-array-with-php/

【讨论】:

【参考方案6】:

PHP 5.3+

usort($array, function($a,$b) return $a['optionNumber']-$b['optionNumber']; );

【讨论】:

【参考方案7】:

使用array_multisortarray_column 的单行解决方案。

//your array
$yourarray = Array
          (
           "0" => Array
                  (
                    "configuration_id" => 10,
                    "id" => 1,
                    "optionNumber" => 3,
                    "optionActive" => 1,
                    "lastUpdated" => "2010-03-17 15:44:12"
                  ),
           "1" => Array
                  (
                    "configuration_id" => 9,
                    "id" => 1,
                    "optionNumber" => 2,
                    "optionActive" => 1,
                    "lastUpdated" => "2010-03-17 15:44:12"
                  ),
           "2" => Array
                  (
                    "configuration_id" => 8,
                    "id" => 1,
                    "optionNumber" => 1,
                    "optionActive" => 1,
                    "lastUpdated" => "2010-03-17 15:44:12"
                  )
);

//access optionNumber in the child arrays using array_column
array_multisort(array_column($yourarray, 'optionNumber'), SORT_ASC, $yourarray);

//print out preformatted
echo "<pre>"; print_r($images); echo "</pre>";

【讨论】:

以上是关于PHP按子数组值排序数组的主要内容,如果未能解决你的问题,请参考以下文章

在javascript中按子数组属性值对对象数组进行排序

按子数组的大小对多维数组进行排序

按子数组值对数组进行分组

linq 按子字符串对数组中的字符串进行排序

Swift 2.0 - 按子数组重新排列 JSON 对象

二维数组中按子数组首个元素值去重