[英]Sort multidimensional array on column values DESC, then by length of another column DESC
我需要对一些不是来自数据库但结构类似于 sql 结果集的数据进行排序。
在 MySQL 中,我将编写如下查询以按两列对数据进行排序:
SELECT product, qty FROM stock ORDER BY qty DESC, LENGTH(product) DESC
但是,在这种情况下,我需要使用 php 执行此排序逻辑。 具体来说,行首先按qty
降序排序,然后按name
的长度降序排序。
未排序的输入:
[
['name' => 'foo bar', 'qty' => 6],
['name' => 'foo bar bar foo', 'qty' => 10],
['name' => 'b', 'qty' => 5],
['name' => 'foo', 'qty' => 10],
['name' => 'bar', 'qty' => 6],
['name' => 'foo bar bar bar foo', 'qty' => 6],
]
排序后,我需要使用name
值作为键, qty
值作为平面关联数组的值重构数据 完成的数组将如下所示:
期望输出:
[
'foo bar bar foo' => 10,
'foo' => 10,
'foo bar bar bar foo' => 6,
'foo bar' => 6,
'bar' => 6,
'b' => 5
]
看看 php 的usort
和uasort
。
您应该能够定义一个可以像这样对其进行排序的函数
不确定它是否可以轻松地与当前阵列一起使用,但它会
$array = array(
array('name' => 'foo bar bar foo', 'qty' => 10 ),
array('name' => 'foo', 'qty' => 6),
array('name' => 'foo bar bar foo', 'qty' => 6 ),
array('name' => 'foo bar', 'qty' => 6 )
);
uasort($array, 'arraySort');
function arraySort($a, $b)
{
if($a['qty'] > $b['qty'])
return 1;
elseif($a['qty'] < $b['qty'])
return -1;
else
if(strlen($a['name']) >= strlen($b['name']))
return 1;
else
return -1;
}
查看这个问题的答案: PHP array multiple sort - by value then by key? ,看来array_multisort
是要走的路。 (我不太确定array_multisort
是如何工作的,我只是稍微修改了一下,它似乎有效)。
试试这个:
$arr = array(
'foo bar' => 6,
'foo' => 10,
'bar' => 6,
'b' => 5,
'foo bar bar bar foo' => 6,
'foo bar bar foo' => 10
);
array_multisort(array_values($arr), SORT_DESC,
array_map(create_function('$v', 'return strlen($v);'), array_keys($arr)),
SORT_DESC, $arr);
演示: http : //codepad.org/mAttNIV7
更新:添加了array_map
以使其按字符串的长度排序,然后才执行:
$str1 > $str2
而不是strlen($str1) > strlen($str2)
。
更新 2:在 PHP >= 5.3 中,您可以用真正的匿名函数替换create_function
。
array_map(function($v){return strlen($v);}, array_keys($arr))
演示 2: http : //codepad.viper-7.com/6qrFwj
根据长度对键进行排序时的一个限制是:不重新排序等长键。 假设我们需要按长度descending
对键进行排序。
$arr = array(
"foo 0" => "apple",
"foo 1" => "ball",
"foo 2 foo 0 foo 0" => "cat",
"foo 2 foo 0 foo 1 foo 0" => "dog",
"foo 2 foo 0 foo 1 foo 1" => "elephant",
"foo 2 foo 1 foo 0" => "fish",
"foo 2 foo 1 foo 1" => "giraffe"
);
debug($arr, "before sort");
$arrBad = $arr;
sortKeysDescBAD($arrBad);
debug($arrBad, "after BAD sort");
sortKeysDescGOOD($arr);
debug($arr, "after GOOD sort 2");
function sortKeysDescBAD(&$arrNew) {
$arrKeysLength = array_map('strlen', array_keys($arrNew));
array_multisort($arrKeysLength, SORT_DESC, $arrNew);
//return max($arrKeysLength);
}
function sortKeysDescGOOD(&$arrNew) {
uksort($arrNew, function($a, $b) {
$lenA = strlen($a); $lenB = strlen($b);
if($lenA == $lenB) {
// If equal length, sort again by descending
$arrOrig = array($a, $b);
$arrSort = $arrOrig;
rsort($arrSort);
if($arrOrig[0] !== $arrSort[0]) return 1;
} else {
// If not equal length, simple
return $lenB - $lenA;
}
});
}
function debug($arr, $title = "") {
if($title !== "") echo "<br/><strong>{$title}</strong><br/>";
echo "<pre>"; print_r($arr); echo "</pre><hr/>";
}
输出将是:
before sort
Array
(
[foo 0] => apple
[foo 1] => ball
[foo 2 foo 0 foo 0] => cat
[foo 2 foo 0 foo 1 foo 0] => dog
[foo 2 foo 0 foo 1 foo 1] => elephant
[foo 2 foo 1 foo 0] => fish
[foo 2 foo 1 foo 1] => giraffe
)
after BAD sort
Array
(
[foo 2 foo 0 foo 1 foo 0] => dog
[foo 2 foo 0 foo 1 foo 1] => elephant
[foo 2 foo 0 foo 0] => cat
[foo 2 foo 1 foo 0] => fish
[foo 2 foo 1 foo 1] => giraffe
[foo 0] => apple
[foo 1] => ball
)
after GOOD sort
Array
(
[foo 2 foo 0 foo 1 foo 1] => elephant
[foo 2 foo 0 foo 1 foo 0] => dog
[foo 2 foo 1 foo 1] => giraffe
[foo 2 foo 1 foo 0] => fish
[foo 2 foo 0 foo 0] => cat
[foo 1] => ball
[foo 0] => apple
)
注意例如(或其他) elephant
和dog
在两种排序方法中的顺序。 第二种方法看起来更好。 可能有更简单的方法来解决这个问题,但希望这可以帮助某人...
从类似于 sql 结果集的输入数组开始,您可以干净地使用包含 3 路比较的usort()
然后是条件辅助 3 路比较。 完成后,您可以将数据的qty
列隔离为值,并且(假设所有name
值都是唯一的)使用name
列作为使用array_column()
的指定键。 比较时,写$b
左侧的操作和数据$a
上实现按降序排序的权利。
代码:(演示)
$array = [
['name' => 'foo bar bar foo', 'qty' => 6],
['name' => 'bah', 'qty' => 5],
['name' => 'foo foo bar foo', 'qty' => 10],
['name' => 'foo', 'qty' => 6],
['name' => 'foo bar', 'qty' => 6],
['name' => 'bar', 'qty' => 11],
];
usort($array, function($a, $b) {
return $b['qty'] <=> $a['qty'] ?: strlen($b['name']) <=> strlen($a['name']);
});
var_export(array_column($array, 'qty', 'name'));
输出:
array (
'bar' => 11,
'foo foo bar foo' => 10,
'foo bar bar foo' => 6,
'foo bar' => 6,
'foo' => 6,
'bah' => 5,
)
使用的优势comparison1 ?: comparison2
的是,在函数调用comparison2
不被执行,除非抢七是必要的-这提高了效率。 或者,使用array_multisort()
将无条件地对所有qty
值调用strlen()
—— 即使它们不需要进行排序。
使用单个宇宙飞船运算符执行排序是完全有效的,但每次进行比较时,以下技术将进行两次函数调用。 这将比我上面的代码段效率低,所以我不推荐以下代码段。
usort($array, function($a, $b) {
return [$b['qty'], strlen($b['name']] <=> [$a['qty'], strlen($a['name'])];
});
ps 当然这也可以用array_multisort()
来完成,我只是发现语法不那么简洁。
array_multisort(
array_column($array, 'qty'),
SORT_DESC,
array_map(
function($row) {
return strlen($row['name']);
},
$array
),
SORT_DESC,
$array
);
var_export(array_column($array, 'qty', 'name'));
在 php 中使用 sort 函数。 确保使用 TRUE 作为第二个参数来保留密钥。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.