简体   繁体   English

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

[英]PHP array multiple sort - by value then by key?

I have an array of string keys with numeric values for use in a list of tags with the number of occurances of each tag, thus:我有一个带有数值的字符串键数组,用于带有每个标签出现次数的标签列表,因此:

$arrTags['mango'] = 2; 
$arrTags['orange'] = 4; 
$arrTags['apple'] = 2; 
$arrTags['banana'] = 3;

this is so i can display the tag list in descending occurance order thus:这样我就可以按降序显示标签列表,因此:

orange (4)  
banana (3) 
mango (2) 
apple (2)

i can use arsort to reverse sort by the value which is brilliant but i also want any tags that have the same numeric value to be sorted alphabetically, so the final result can be:我可以使用arsort按很棒的值进行反向排序,但我也希望任何具有相同数值的标签按字母顺序排序,因此最终结果可以是:

orange (4)  
banana (3) 
apple (2) 
mango (2)

is there a way i can do this?有没有办法做到这一点? i'm guessing that usort may be the way to go but i look at the examples on php.net and my eyes glaze over!我猜usort可能是要走的路,但我看着 php.net 上的例子,我的眼睛呆滞了! many thanks!!!非常感谢!!!

As Scott Saunders hints in his comment to David's solution, you can use the array_keys() and array_values() functions to get rid of the loop.正如 Scott Saunders 在他对 David 解决方案的评论中所暗示的那样,您可以使用 array_keys() 和 array_values() 函数来摆脱循环。 In fact, you can solve this in one line of code:事实上,你可以用一行代码解决这个问题:

array_multisort(array_values($arrTags), SORT_DESC, array_keys($arrTags), SORT_ASC, $arrTags);

Have a look at examples #3: http://php.net/manual/en/function.array-multisort.php看看例子#3: http : //php.net/manual/en/function.array-multisort.php

You'll need to create two arrays to use as indexes;您需要创建两个数组以用作索引; one made up of the original array's keys and the other of the original array's values.一个由原始数组的键和另一个原始数组的值组成。

Then use multisort to sort by text values (keys of the original array) and then by the numeric values (values of the original array).然后使用 multisort 按文本值(原始数组的键)排序,然后按数值(原始数组的值)排序。

SOLVED解决了

After a little experimentation I discovered that array_multisort does the trick nicely:经过一些实验,我发现array_multisort很好地完成了这个技巧:

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

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

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

:) :)

The previous proposed solution seems logical, but it just doens't work:先前提出的解决方案似乎合乎逻辑,但它不起作用:

ksort($arrTags);
arsort($arrTags);

The complete PHP code to realize the asked sorting, will be:实现查询排序的完整 PHP 代码为:

$k = array_keys($arrTags);
$v = array_values($arrTags);
array_multisort($k, SORT_ASC, $v, SORT_DESC);
$arrTags = array_combine($k, $v);

Please note that array_multisort() uses references on user input, so you'll have to use two temporary variabels ($k and $v) to supply content as user input.请注意,array_multisort() 在用户输入上使用引用,因此您必须使用两个临时变量($k 和 $v)来提供内容作为用户输入。 This way array_multisort() can change the content.这样 array_multisort() 可以改变内容。 Later on, rebuild the sorted array via array_combine().稍后,通过 array_combine() 重建排序后的数组。

I've built a reusable function to accomplish this task:我已经构建了一个可重用的函数来完成这个任务:

<?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 is correct re: using array_multisort vs. ksort, arsort SlappyTheFish 是正确的:使用 array_multisort 与 ksort,arsort

In David's example ksort, arsort works fine, however if the keys' string values contain characters other than alphabetic characters, the sort may not work as intended.在 David 的示例 ksort 中,arsort 工作正常,但是如果键的字符串值包含字母字符以外的字符,则排序可能无法按预期工作。

ex:前任:

$arrTags['banana'] = 3;
$arrTags['mango'] = 2;
$arrTags['apple1'] = 2;
$arrTags['orange'] = 4;
$arrTags['almond1'] = 2;

ksort($arrTags);
arsort($arrTags);

print_r($arrTags);

returns:返回:

Array
(
    [orange] => 4
    [banana] => 3
    [apple1] => 2
    [mango] => 2
    [almond1] => 2
)

however using:但是使用:

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

returns:返回:

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);

Must be ok.一定没问题。

Use uksort() to pass the keys into the custom function's scope;使用uksort()将键传递到自定义函数的作用域中; within that scope, access the associated value by using the key on the passed in (full) array.在该范围内,使用传入(完整)数组上的键访问关联值。

The advantage of this is the time complexity -- this will be more direct than two separate sorting function calls and doesn't require the setup of array_multisort() .这样做的好处是时间复杂度——这将比两个单独的排序函数调用更直接,并且不需要设置array_multisort()

Although the spaceship (3-way) operator was not available back when this question was asked, it is now and it makes the comparison much easier/cleaner now.尽管在提出这个问题时,宇宙飞船(3 路)操作员不可用,但现在可用,并且现在使比较更容易/更清晰。

From PHP7.4 and up, the syntax is very concise.从 PHP7.4 开始,语法非常简洁。 ( Demo ) 演示

uksort($arrTags, fn($a, $b) => [$arrTags[$b], $a] <=> [$arrTags[$a], $b]);

From PHP7.0 - PHP7.3, you must pass in the main array with use() .从 PHP7.0 - PHP7.3 开始,您必须use()传入主数组。 ( Demo ) 演示

uksort(
    $arrTags,
    function($a, $b) use ($arrTags) {
        return [$arrTags[$b], $a] <=> [$arrTags[$a], $b];
    }
);

You're thinking too complicated:你想的太复杂了:

ksort($arrTags);
arsort($arrTags);

Now your array is sorted like you want it to.现在您的数组已按照您希望的方式排序。

Note: This technique is only reliable in PHP7 and up: https://3v4l.org/ma7ab注意:此技术仅在 PHP7 及更高版本中可靠: https ://3v4l.org/ma7ab

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM