我有一个带有数值的字符串键数组,用于创建一个标签列表,其中每个标签的出现次数与此类似:
$arrTags = [
'mango' => 2,
'orange' => 4,
'apple' => 2,
'banana' => 3
];
我想在列表中显示具有降序值的标签,然后 标签名称升序生成:
orange (4)
banana (3)
apple (2)
mango (2)
arsort()
不合适,因为它会将 mango
放在 apple
之前。我猜 usort()
可能就是这样,但我在 php.net 的评论中没有找到合适的例子。
正如 Scott Saunders 在对 David 解决方案的评论中暗示的那样,您可以使用 array_keys() 和 array_values() 函数来摆脱循环。事实上,你可以用一行代码解决这个问题:
array_multisort(array_values($arrTags), SORT_DESC, array_keys($arrTags), SORT_ASC, $arrTags);
看一下示例#3: http://php.net/manual/en/function.array-multisort.php
您需要创建两个数组用作索引;一个由原始数组的键组成,另一个由原始数组的值组成。
然后使用 multisort 按文本值(原始数组的键)排序,然后按数值(原始数组的值)排序。
已解决
经过一些实验,我发现
array_multisort
效果很好:
$tag = array();
$num = array();
foreach($arrTags as $key => $value){
$tag[] = $key;
$num[] = $value;
}
array_multisort($num, SORT_DESC, $tag, SORT_ASC, $arrTags);
:)
之前提出的解决方案似乎合乎逻辑,但它就是行不通:
ksort($arrTags);
arsort($arrTags);
实现要求排序的完整PHP代码为:
$k = array_keys($arrTags);
$v = array_values($arrTags);
array_multisort($k, SORT_ASC, $v, SORT_DESC);
$arrTags = array_combine($k, $v);
请注意 array_multisort() 使用用户输入的引用,因此您必须使用两个临时变量($k 和 $v)来提供内容作为用户输入。这样 array_multisort() 就可以改变内容。稍后,通过 array_combine() 重建排序后的数组。
我构建了一个可重用的函数来完成此任务:
<?php
/**
* Sort a multi-dimensional array by key, then by value.
*
* @param array Array to be sorted
* @param int One of the available sort options: SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
* @param int One of the available sort options: SORT_ASC, SORT_DESC, SORT_REGULAR, SORT_NUMERIC, SORT_STRING
* @return void
* @example The following array will be reordered:
* $a = array(
* 'd' => 4,
* 'c' => 2,
* 'a' => 3,
* 'b' => 1,
* 'e' => 2,
* 'g' => 2,
* 'f' => 2,
* );
* SortArrayByKeyThanValue($a); # reorder array to: array(
* 'b' => 1,
* 'c' => 2,
* 'e' => 2,
* 'f' => 2,
* 'g' => 2,
* 'a' => 3,
* 'd' => 4,
* );
* @author Sijmen Ruwhof <sijmen(a)secundity.com>
* @copyright 2011, Secundity
*/
function SortArrayByKeyThanValue (&$pArray, $pSortMethodForKey = SORT_ASC, $pSortMethodForValue = SORT_ASC)
{
# check user input: sorting is not necessary
if (count($pArray) < 2)
return;
# define $k and $v as array_multisort() needs real variables, as user input is put by reference
$k = array_keys ($pArray);
$v = array_values($pArray);
array_multisort(
$v, $pSortMethodForValue,
$k, $pSortMethodForKey
);
$pArray = array_combine($k, $v);
}
?>
SlappyTheFish 是正确的:使用 array_multisort 与 ksort、arsort
在 David 的示例 ksort 中,arsort 工作正常,但是如果键的字符串值包含字母字符以外的字符,则排序可能无法按预期工作。
例如:
$arrTags['banana'] = 3;
$arrTags['mango'] = 2;
$arrTags['apple1'] = 2;
$arrTags['orange'] = 4;
$arrTags['almond1'] = 2;
ksort($arrTags);
arsort($arrTags);
print_r($arrTags);
返回:
Array
(
[orange] => 4
[banana] => 3
[apple1] => 2
[mango] => 2
[almond1] => 2
)
但是使用:
$arrTags['banana'] = 3;
$arrTags['mango'] = 2;
$arrTags['apple1'] = 2;
$arrTags['orange'] = 4;
$arrTags['almond1'] = 2;
$tag = array();
$num = array();
foreach($arrTags as $key => $value){
$tag[] = $key;
$num[] = $value;
}
array_multisort($num, SORT_DESC, $tag, SORT_ASC, $arrTags);
print_r($arrTags);
返回:
Array
(
[orange] => 4
[banana] => 3
[almond1] => 2
[apple1] => 2
[mango] => 2
)
//preserve arrays keys for later use
$ar1= array_keys($your_array);
//preserve array's values for later use
$ar2= array_values($your_array);
//perform sorting by value and then by key
array_multisort($ar2, SORT_DESC, $ar1, SORT_DESC);
//combine sorted values and keys arrays to new array
$sorted_array = array_combine($ar1, $ar2);
一定没问题。
使用
uksort()
将键传递到自定义函数的范围内;在该范围内,通过使用传入(完整)数组上的键来访问关联的值。
这样做的优点是时间复杂度——这比两个单独的排序函数调用更直接,并且不需要
array_multisort()
的设置。另外,array_multisort()
会破坏数字键(并不是提问者的键是数字)https://3v4l.org/rQak4。
虽然在提出这个问题时宇宙飞船(3 向)操作员不可用,但现在可以使用,这使得现在的比较变得更容易/更清晰。
从PHP7.4开始,语法非常简洁。 (演示)
uksort($arrTags, fn($a, $b) => [$arrTags[$b], $a] <=> [$arrTags[$a], $b]);
从 PHP7.0 - PHP7.3 开始,必须使用
use()
传入主数组。 (演示)
uksort(
$arrTags,
function($a, $b) use ($arrTags) {
return [$arrTags[$b], $a] <=> [$arrTags[$a], $b];
}
);
你想得太复杂了:
ksort($arrTags);
arsort($arrTags);
现在你的数组已按照你想要的方式排序了。
注意:此技术仅在 PHP7 及更高版本中可靠:https://3v4l.org/ma7ab