Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP数组多重排序-按值然后按键?_Php_Sorting_Arrays - Fatal编程技术网

PHP数组多重排序-按值然后按键?

PHP数组多重排序-按值然后按键?,php,sorting,arrays,Php,Sorting,Arrays,我有一个带有数值的字符串键数组,用于标记列表中,每个标记的出现次数如下: $arrTags['mango'] = 2; $arrTags['orange'] = 4; $arrTags['apple'] = 2; $arrTags['banana'] = 3; 因此,我可以按降序显示标记列表,因此: orange (4) banana (3) mango (2) apple (2) 我可以使用arsort按值进行反向排序,这是非常出色的,但我也希望所有具有相同数值的标记按字母顺

我有一个带有数值的字符串键数组,用于标记列表中,每个标记的出现次数如下:

$arrTags['mango'] = 2; 
$arrTags['orange'] = 4; 
$arrTags['apple'] = 2; 
$arrTags['banana'] = 3;
因此,我可以按降序显示标记列表,因此:

orange (4)  
banana (3) 
mango (2) 
apple (2)
我可以使用arsort按值进行反向排序,这是非常出色的,但我也希望所有具有相同数值的标记按字母顺序排序,因此最终结果可以是:

orange (4)  
banana (3) 
apple (2) 
mango (2)
我有办法做到这一点吗?我猜usort可能是一个不错的选择,但当我看到php.net上的例子时,我的眼睛都呆呆了!非常感谢

看看例子#3:

您需要创建两个数组用作索引;一个由原始数组的键和另一个原始数组的值组成


然后使用multisort按文本值(原始数组的键)排序,然后按数字值(原始数组的值)排序。

您认为太复杂了:

ksort($arrTags);
arsort($arrTags);
现在,您的数组已按所需进行排序


注意:此技术仅在PHP7及以上版本中可靠:已解决

经过一点实验,我发现
array\u multisort
很好地实现了这一点:

$tag = array(); 
$num = array();

foreach($arrTags as $key => $value){ 
$tag[] = $key; 
$num[] = $value; 
}

array_multisort($num, SORT_DESC, $tag, SORT_ASC, $arrTags);

:)

SlappyTheFish是正确的:使用数组\u multisort vs.ksort,arsort

在David的示例ksort中,arsort可以正常工作,但是如果键的字符串值包含字母字符以外的字符,则排序可能无法正常工作

例:

返回:

Array
(
    [orange] => 4
    [banana] => 3
    [apple1] => 2
    [mango] => 2
    [almond1] => 2
)
Array
(
    [orange] => 4
    [banana] => 3
    [almond1] => 2
    [apple1] => 2
    [mango] => 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
    [apple1] => 2
    [mango] => 2
    [almond1] => 2
)
Array
(
    [orange] => 4
    [banana] => 3
    [almond1] => 2
    [apple1] => 2
    [mango] => 2
)

正如Scott Saunders在对David的解决方案的评论中所暗示的,您可以使用array_keys()和array_values()函数来消除循环。事实上,您可以在一行代码中解决此问题:

array_multisort(array_values($arrTags), SORT_DESC, array_keys($arrTags), 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);
}
?>

必须正常。

使用
uksort()
将键传递到自定义函数的作用域中;在该范围内,使用传入(完整)数组上的键访问关联值

这样做的优点是时间复杂度——这比两个单独的排序函数调用更直接,并且不需要设置
array\u multisort()

虽然当问到这个问题时,飞船(三向)操作员不在,但现在是,这使比较变得更容易/更清晰了

从PHP7.4到更高版本,语法非常简洁。()


我正要发布这个确切的答案。无论如何,我已经尝试过了,我可以确认它是有效的。php排序不稳定,所以不能保证它会有效@克里斯,这是真的,但我仍然没有发现任何情况下,它不会工作,所以我会继续这个。谢谢你的想法,但它不适合我。它对数字的降序进行了很好的排序,但是对相同数值的键排序是非常随机的,当然不是按字母排序的。不知道为什么。那将是斯帕皮菲鱼的答案,对吗?我认为您应该将该答案标记为已接受,然后查看array\u keys()和array\u values()函数以摆脱循环$num=数组_值($arrTags)将形成没有循环的相同数组。为什么这对我不起作用?我复制了上面的示例,解决方案在问题中得到了相同的结果。@TimYao您的键是数字键吗@那么,什么是不复杂的解决方案呢?请参阅@Jon Bernhardt bellow以获得一个很好的实现示例。感谢您的代码。我有原来问题的确切情况,这对我很有用。困扰我的是,我不确定这里到底发生了什么。最后一个参数的功能是什么?我可以看到,最后一个参数(通过引用传递)是返回已更改数组的唯一可能,OK。但是,数组集如何相互关联?当multisort从左向右执行其工作时,后续数组将与它们一起排序。如果是这样,则所有阵列必须具有文档中不要求的相同长度#confused@andypotter:基本上,
array\u multi\u sort()
将在内部创建另一个数组
$indirect
,其中每个索引是一个包含所提供数组的所有值的数组:
$indirect[$i]=[$v1,$v2,$v3,…,NULL]
。然后,使用一个特殊的比较函数对数组应用快速排序,该函数将首先将
$indirect[$a][$r]
$indirect[$b][$r]
进行比较,其中
$r==0
如果它们相等,
$r
将增加,直到
$indirect[$a][$r]
null
(已使用所有提供的数组)。最后,根据
$indirect
重写每个数组。如果使用不同大小的数组,则返回FALSE。@dearsina:这一点很好。然而,OP特别提到了字符串键。事实上,他要求“任何具有相同数值的标记……按字母顺序排序”。这是唯一一个在键是数字时有效的解决方案。这个答案是不正确的:看看它是如何不按值排序的?此答案实际上与
ksort()
的排序相同。此答案具有误导性,不再是最新答案。从PHP7和更高版本中,
ksort()然后是arsort()
将正确排序数组。正是PHP7之前的排序算法使得该技术不可靠。重要的是,这种不同的行为与键中存在的数字无关。查看此演示:请更新您的答案,使其正确且最新。此刻
uksort($arrTags, fn($a, $b) => [$arrTags[$b], $a] <=> [$arrTags[$a], $b]);
uksort(
    $arrTags,
    function($a, $b) use ($arrTags) {
        return [$arrTags[$b], $a] <=> [$arrTags[$a], $b];
    }
);