按字母排序,然后按数字Laravel集合排序



我正在寻找一种方法来对集合进行排序,使以字母表开头的名称值位于顶部,然后命名以数字开头的值。例如:

$collection = collect([
['name' => 'b', 'symbol' => '#'],
['name' => '2a', 'symbol' => '$'],
['name' => '1', 'symbol' => '@'],
['name' => 'a', 'symbol' => '%']
]);

上面的集合应该这样排序:

[
[
"name" => "a",
"symbol" => "%",
],
[
"name" => "b",
"symbol" => "#",
],
[
"name" => "1",
"symbol" => "@",
],
[
"name" => "2a",
"symbol" => "$",
],
]

但这就是我使用sortBy方法进行排序时得到的结果:

$collection->sortBy('name')->values()->all();
[
[
"name" => "1",
"symbol" => "@",
],
[
"name" => "2a",
"symbol" => "$",
],
[
"name" => "a",
"symbol" => "%",
],
[
"name" => "b",
"symbol" => "#",
],
]

你知道如何对这个集合进行排序,让以字母开头的名字排在第一位吗?

您需要定义自己的自定义比较器函数来使用sort对这些集合对象进行排序。

通过检查两个名字是否都是字母来比较。如果两者都是字母表,那么使用strcasecmp进行常规字符串比较就足够了。如果它们中的任何一个是字母表,则通过返回值-1将它们推到更高的级别,这意味着在排序顺序中位于上面。如果两者都是数字或字母数字,请再次使用strcasecmp

<?php
$collection = collect([
['name' => 'b', 'symbol' => '#'],
['name' => '2a', 'symbol' => '$'],
['name' => '1', 'symbol' => '@'],
['name' => 'a', 'symbol' => '%']
]);
$collection = $collection->sort(function($a,$b){
$a_is_alphabet = preg_match('/^[a-zA-Z]+$/', $a['name']) === 1;
$b_is_alphabet = preg_match('/^[a-zA-Z]+$/', $b['name']) === 1;
if($a_is_alphabet && $b_is_alphabet){
return strcasecmp($a['name'], $b['name']);
}elseif($a_is_alphabet){
return -1;
}elseif($b_is_alphabet){
return 1;
}
return strcasecmp($a['name'], $b['name']);
});

如果希望纯字母名称值具有最高优先级,那么我假设自然排序,比如a2a10之前。只需在sort()方法调用的自定义回调中编写两条规则。

在对ASC排序时,假求值在真求值之前排序,因此只需在$a元素之前写入$b元素即可对DESC排序。要打破第一次比较的任何联系,请调用strnatcmp()

Laravel早在2019年就采用了箭头函数语法。

代码:(基本PHP演示(

$collection->sort(fn($a, $b) =>
(ctype_alpha($b['name']) <=> ctype_alpha($a['name']))
?: strnatcmp($a['name'], $b['name'])
);

如果只想检查第一个字符是否是字母,可以使用$a['name'][0]$b['name'][0]。如果字符串的第一个字符可能是多字节的,那么regex方法可能是最好的。

最新更新