返回

PHP 排序数组:先按键升序,再按值升序

php

排序数组:先按键升序,再按值升序

处理键值对数组的排序问题是常见任务。当需要先按键的字母顺序升序排列,再按值的升序排列时,需要组合使用排序函数,或者利用自定义排序实现。直接使用 ksort()arsort() 无法达到预期效果,因为它们各自独立排序,没有建立键值之间的关联。下文将提供几种方法来解决这个问题。

方法一: 使用 uksort() 进行自定义排序

uksort() 函数允许使用用户自定义的比较函数对数组的键进行排序。通过在比较函数中同时考虑键和值,可以实现先按键排序再按值排序。

原理:

uksort() 遍历数组,并将每对键传递给用户定义的比较函数。比较函数返回一个整数,指示键的相对顺序:负数表示第一个键小于第二个键,零表示相等,正数表示第一个键大于第二个键。

在比较函数中,首先比较键。如果键不相等,则返回键的比较结果。如果键相等,则比较值,并返回值的比较结果。

代码示例:

<?php
$data = array(
    "a" => 2,
    "c" => 1,
    "b" => 3
);

uksort($data, function ($key1, $key2) use ($data) {
    $keyComparison = strcmp($key1, $key2);
    if ($keyComparison !== 0) {
        return $keyComparison;
    } else {
        return $data[$key1] - $data[$key2];
    }
});

print_r($data);
//输出
//Array
//(
//    [a] => 2
//    [b] => 3
//    [c] => 1
//)
?>

操作步骤:

  1. 定义一个包含键值对的关联数组 $data
  2. 使用 uksort() 函数,传入 $data 数组和一个匿名函数作为参数。
  3. 匿名函数接收两个键 $key1$key2 作为参数,并使用 use ($data) 来访问数组本身。
  4. 首先,使用 strcmp() 函数比较两个键的字母顺序。
  5. 如果键不相同 ($keyComparison !== 0),则直接返回键的比较结果。
  6. 如果键相同,则根据值的大小进行比较,返回 $data[$key1] - $data[$key2]
  7. 排序后, $data 数组将按照键的升序排列,如果键相同,则按照值的升序排列。

安全建议:

在使用 uksort() 时,需要确保比较函数不会抛出异常,并且对任何输入都能够返回预期的结果。避免在比较函数中执行可能导致安全问题或性能问题的操作,例如数据库查询或网络请求。

方法二: 先按键排序,再分组,最后合并

此方法思路是将数组先按键排序,然后按照值的顺序将具有相同键的值分组,最后合并这些分组,实现先按键后值的排序。

原理:

该方法分三个步骤:

  1. 按键排序: 使用 ksort() 函数按键的字母顺序对数组进行排序。
  2. 按值分组: 遍历排序后的数组,将具有相同键的元素分组到子数组中。
  3. 合并分组: 将分组后的子数组按照值的升序重新排序并合并,构建最终的排序数组。

代码示例:

<?php
$data = array(
    "a" => 2,
    "c" => 1,
    "b" => 3,
     "a" => 1
);

ksort($data);

$grouped = [];
foreach ($data as $key => $value) {
    $grouped[$key][] = $value;
}

$result = [];
foreach ($grouped as $key => $values) {
    sort($values);
    foreach ($values as $value) {
        $result[$key] = $value;
    }
}

print_r($result);

//输出
//Array
//(
//    [a] => 1
//    [b] => 3
//    [c] => 1
//)
?>

操作步骤:

  1. 定义一个包含键值对的关联数组 $data
  2. 使用 ksort($data) 对数组按键进行升序排序。
  3. 初始化一个空数组 $grouped,用于按键分组。
  4. 遍历排序后的数组,将具有相同键的值追加到 $grouped 数组中相应的键中。
  5. 初始化一个空数组 $result,用于存储最终结果。
  6. 遍历分组后的数组 $grouped,对每个键的值数组使用 sort($values) 按值升序排序。
  7. 将排序后的值重新赋给 $result 数组,保持键的顺序。

安全建议:

该方法需要额外的内存来存储分组后的数组。当处理大型数组时,需要注意内存使用情况。此外,需要确保分组和合并的逻辑正确,以避免意外的结果。

方法三: 使用辅助数组排序

通过创建一个辅助数组,存储键和值,然后使用 usort() 函数对辅助数组进行自定义排序,最后根据辅助数组重建排序后的结果数组。

原理:

这种方法首先将原始数组的键和值提取到新的辅助数组中,每个元素包含一个键和一个值。然后,使用usort()对这个辅助数组进行排序。在自定义排序函数中,先比较键,再比较值。最后,根据排序后的辅助数组重建一个新的关联数组。

代码示例:

<?php
$data = array(
    "a" => 2,
    "c" => 1,
    "b" => 3
);

$helper = [];
foreach ($data as $key => $value) {
    $helper[] = ['key' => $key, 'value' => $value];
}

usort($helper, function ($a, $b) {
    $keyComparison = strcmp($a['key'], $b['key']);
    if ($keyComparison !== 0) {
        return $keyComparison;
    } else {
        return $a['value'] - $b['value'];
    }
});

$result = [];
foreach ($helper as $item) {
    $result[$item['key']] = $item['value'];
}

print_r($result);
//输出
//Array
//(
//    [a] => 2
//    [b] => 3
//    [c] => 1
//)
?>

操作步骤:

  1. 定义一个包含键值对的关联数组 $data
  2. 创建一个空数组 $helper
  3. 遍历原始数组 $data,将每个键值对转换为包含 'key''value' 的关联数组,并将其添加到 $helper 数组中。
  4. 使用 usort() 函数对 $helper 数组进行排序,并传入一个匿名比较函数。
  5. 比较函数接收两个参数 $a$b,它们是 $helper 数组中的元素。
  6. 在比较函数中,首先比较 'key' 的值,使用 strcmp() 函数进行字符串比较。
  7. 如果 'key' 不相同,则返回键的比较结果。
  8. 如果 'key' 相同,则比较 'value' 的值,返回它们的差。
  9. 排序后, $helper 数组将按照先键后值的顺序排列。
  10. 创建一个空数组 $result
  11. 遍历排序后的 $helper 数组,将键值对重新添加到 $result 数组中。

安全建议:

这种方法会创建一个新的辅助数组,增加内存的使用。在处理大型数组时,需要考虑内存消耗。另外,确保自定义排序函数的逻辑正确,以获得预期的排序结果。

总结

以上介绍了三种解决 “Sort array by keys ASC, then values ASC” 问题的方法。根据实际情况选择合适的方法,如对性能有较高要求,可以优先考虑使用 uksort() ,而对内存有限制时,则可以考虑先排序再分组的方法。理解这些方法的原理有助于在实际开发中灵活运用,解决类似的数组排序问题。