当前位置: 首页> 最新文章列表> 如何使用 uksort 排序时避免重排序相同的键

如何使用 uksort 排序时避免重排序相同的键

gitbox 2025-05-31

一、uksort()函数简介

uksort(array &$array, callable $callback): bool函数对数组的键进行排序。$callback是用户自定义的比较函数,接受两个键名作为参数,返回小于、等于或大于零的值,决定排序顺序。

示例代码:

$array = [
    'apple' => 1,
    'banana' => 2,
    'cherry' => 3,
];

uksort($array, function($a, $b) {
    return strcmp($a, $b);
});

print_r($array);

输出:

Array
(
    [apple] => 1
    [banana] => 2
    [cherry] => 3
)

二、问题描述:相同键导致的重复排序

当键经过某种预处理或映射后,不同的原始键可能被认为是“相同键”,这时候比较函数可能频繁且重复地被调用,影响性能。例如:

$array = [
    'a_1' => 10,
    'a_2' => 20,
    'b_1' => 30,
];

uksort($array, function($key1, $key2) {
    // 只比较下划线前的部分
    $part1 = explode('_', $key1)[0];
    $part2 = explode('_', $key2)[0];
    return strcmp($part1, $part2);
});

此时,'a_1''a_2'会被视为“相同键”,比较函数可能多次对它们进行比较。对于大型数组,这种重复会显著降低效率。

三、避免重复排序的核心思路

避免重复排序,关键是减少比较函数中对相同“逻辑键”的重复计算,甚至避免对等价键的多余比较。常用的做法有:

  1. 缓存映射结果:比较函数内部使用静态缓存,避免重复计算键的映射值。

  2. 先对键进行预处理和去重:先生成一个映射表,对键进行归类,排序时直接用映射结果比较。

  3. 使用辅助数组排序:用映射值作为辅助键,先生成一组映射值,再使用array_multisort()或其他排序函数避免重复调用。

四、具体实现示例

方案一:比较函数内缓存映射

$array = [
    'a_1' => 10,
    'a_2' => 20,
    'b_1' => 30,
    'b_2' => 40,
    'c_1' => 50,
];

uksort($array, function($key1, $key2) {
    static $cache = [];

    if (!isset($cache[$key1])) {
        $cache[$key1] = explode('_', $key1)[0];
    }
    if (!isset($cache[$key2])) {
        $cache[$key2] = explode('_', $key2)[0];
    }

    return strcmp($cache[$key1], $cache[$key2]);
});

print_r($array);

这样,explode('_', $key)操作仅进行一次,避免重复计算,提升性能。

方案二:预处理映射键,辅助排序

$array = [
    'a_1' => 10,
    'a_2' => 20,
    'b_1' => 30,
    'b_2' => 40,
    'c_1' => 50,
];

// 生成映射键数组
$mappedKeys = [];
foreach (array_keys($array) as $key) {
    $mappedKeys[$key] = explode('_', $key)[0];
}

// 按映射键排序键名
uasort($mappedKeys, function($a, $b) {
    return strcmp($a, $b);
});

// 根据排序好的映射键重建主数组
$newArray = [];
foreach ($mappedKeys as $originalKey => $_) {
    $newArray[$originalKey] = $array[$originalKey];
}

print_r($newArray);

该方案避免了在uksort中多次调用比较函数,适合映射规则复杂时使用。


五、总结

  • 使用uksort()时,比较函数会多次被调用,尤其当键需要转换或归类后相等的情况,容易出现重复计算。

  • 通过在比较函数内使用缓存,或者事先对键进行映射排序,能有效避免重复排序,提升性能和代码清晰度。

  • 选择哪种方案取决于数组大小、映射规则复杂度及性能需求。

掌握以上技巧后,你可以更灵活高效地使用uksort()进行复杂键排序。