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

时间:2010-02-17 15:39:58

标签: php sorting arrays

我有一个带有数字值的字符串键数组,用于标签列表中,每个标签都有出现次数,因此:

$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上的例子,我的眼睛茫然!非常感谢!!!

8 个答案:

答案 0 :(得分:33)

正如Scott Saunders在对David的解决方案的评论中暗示的那样,你可以使用array_keys()和array_values()函数来摆脱循环。实际上,您可以在一行代码中解决这个问题:

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

答案 1 :(得分:15)

看一下例子#3: http://php.net/manual/en/function.array-multisort.php

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

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

答案 2 :(得分:14)

<强>解决

经过一些实验后,我发现array_multisort很好地解决了这个问题:

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

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

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

:)

答案 3 :(得分:6)

之前提出的解决方案似乎合乎逻辑,但它只是起作用:

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

答案 4 :(得分:3)

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
)

答案 5 :(得分:1)

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

一定没问题。

答案 6 :(得分:0)

你的想法太复杂了:

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

现在你的数组按你想要的那样排序。

答案 7 :(得分:0)

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

这样做的好处是时间很复杂-比两个单独的排序函数调用更直接,而且不需要设置array_multisort()

尽管问这个问题时还不知道太空飞船(三向)运算符,但现在就可以了,它使比较现在更容易/更简洁。

从PHP7.4起,语法非常简洁。 (Demo

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

在PHP7.0-PHP7.3中,必须使用use()传入主数组。 (Demo

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