按列值对关联数组的数组进行排序

603

考虑以下数组:

$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),

);

我该怎么做呢?


3
可能是如何在 PHP 中对多维数组进行排序的重复问题。 - Jon
1
为什么不直接重构你的输入数组,让 price 列排在第一位,type 列排在第二位呢?这样,你就可以直接调用 rsort() 函数了。https://3v4l.org/2meqs - mickmackusa
排序规范 - mickmackusa
23个回答

7

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

1
在Stack Overflow上,仅包含代码的答案价值较低,因为它们无法很好地教育/赋能OP和成千上万的未来研究人员。此外,建议那些早已提供多年的技术并不会帮助研究人员——事实上,这浪费了他们的研究时间,因为他们最终会阅读更多的内容,但没有获得新的信息。 - mickmackusa
现代的PHP应用程序不应该在自定义回调中返回布尔类型的值;而应该返回一个整数类型的值。 - undefined

5

测试了10万条记录: 通过函数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*
}

8
唯一排序键的要求有点像是一个绝杀条件。如果您有唯一的排序值可以作为键,那么问题来了:为什么不从一开始就用这些键构建数组呢?在OP的情况下,很难想象两个价格相同的物品是不可能的。考虑到这一点,使用这种解决方案会导致数组中的物品神秘地和无声地从排序结果集中消失。 - Chris Baker
@Chris Baker,你说得对。这只适用于唯一的值。但是这种解决方案非常快,所以速度是制作和使用它的原因。目前可能不是实际的,需要使用PHP 7.1.x进行测试。 - Nefelim
array_column()可以完成foreach()所做的工作。如果通过进行键比较来提高性能,需要注意这个方法会通过填充新数组来使内存消耗翻倍,正如Chris Baker所指出的,如果在识别列中遇到重复的值,那么整行数据将会丢失。此外,如果分配的键被PHP截断(使用浮点类型值作为键),可能会导致数据丢失等副作用。 - undefined

5

试一试这个:

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

你好,欢迎来到stackoverflow,并感谢您的回答。虽然这段代码可能回答了问题,但您是否可以考虑添加一些解释,说明您解决的问题以及如何解决它?这将有助于未来的读者更好地理解您的答案并从中学习。 - Plutian
2
请勿重复之前帖子的建议(尤其是在同一页上)。这会使 Stack Overflow 变得臃肿,浪费研究人员的时间。 - mickmackusa

3

这个函数是可重复使用的:

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

默认情况下,它可以很好地处理字符串值,但如果你的所有值都是数字,你需要将回调函数替换为数字比较函数


你将其称为 usortarr,但随后却调用了 uasort 而不是 usort;可能会有些令人困惑。 对于类似问题中展示的具有数字索引的连续数组,后者可能是你实际想要的。 - Mark Amery

2

这是我很久以前发现并稍作整理的一种方法。它非常有效,可以快速地进行对象接受的更改。

/**
 * 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
这种方法是可行的,但比Josh Davis(使用array_multisort)或我的(使用usort)都要冗长得多,并且似乎没有任何优势可以交换。 - Mark Amery
我觉得在专业项目中,我永远不会需要这样的脚本。另请参阅如何使用array_multisort()对大小写不敏感地对多维PHP数组进行排序 - undefined

1

许多人正在寻找使用Laravel实现此操作的方法,并最终到达这里。此外,一些Laravel问题因为与此问题重复而被关闭。

因此,我分享了一种使用Laravel collect()方法执行此操作的简单方法。

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

按降序排列
$inventory = collect($inventory)->sortBy('price')->reverse()->toArray();

或者,

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

1
//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

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


是的。如果我找不到解决方案,我会这样做。我相当确定有一些奇怪的参数可以添加到其中一个排序中以实现此目的。不过还是谢谢你的想法! - Matt
与其他在此发布的答案相比,这个答案更像是一个“提示”,应该作为评论放在问题下面,而不是作为答案。 - mickmackusa

0

这个函数在所有主要版本的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;
    }

0

完整的动态函数 我在寻找关联数组排序时发现了这个令人惊叹的函数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

foreach()之前,if (count($array) > 0) {是不必要的。这个脚本是否过度设计了?我不确定我会使用这样的脚本,而不是使用原生的array_multisort()usort()函数。 - undefined

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