尝试按带有特殊字符的子值对多维数组进行排序


Trying to sort a multidimensional array, by a sub-value with special characters

我曾经有一个包含国家列表的PHP数组:

$countries = array(
  'AX' => 'Åland Islands',
  'AF' => 'Afghanistan',
  'GB' => 'United Kingdom'
);
$collator = collator_create('en');
collator_asort($collator, $countries, Collator::SORT_STRING);

显然这个列表对于这个例子来说要短得多,但是这里的排序是有效的。我期待并得到:

    阿富汗
  • 奥兰群岛
  • 英国

然而,我需要添加更多的数据,它变成了多维的:

$countries = array(
  array(
    'name' => 'Åland Islands',
    'code' => 'AX'
  ),
  array(
    'name' => 'Afghanistan',
    'code' => 'AF'
  ),
  array(
    'name' => 'United Kingdom',
    'code' => 'GB'
  )
);
usort($countries, function($a, $b){ return $a['name'] <=> $b['name']; });

它对列表中的其他国家进行排序,但给我这个:

    阿富汗
  • 英国
  • 奥兰群岛

我无论如何也想不出如何正确地把这个分类。我意识到没有排序器在当前状态下被调用或应用,但是有一种方法可以使排序器在多维环境中工作吗?

下面是基于初始方法的可能修复:

usort($countries, function($a, $b) {
  $collator = collator_create('en');
  $arr = array($a['name'], $b['name']);
  collator_asort($collator, $arr, Collator::SORT_STRING);
  return array_pop($arr) == $a['name'];
});

为了在长列表上获得最佳性能,您可能只希望在匿名函数的作用域之外实例化$collator一次。

对于多维数组,我们可以使用collator_compare()函数定义自定义排序函数:

$collator = new Collator('en');
usort($countries, function($a, $b) use ($collator) {
    return $collator->compare($a['name'], $b['name']);
});

若要对"country list"进行排序而不包含Collator,则应将所有带有重音字符的单词转换为其ASCII表示(例如:ÅA)使用iconv函数:

usort($countries, function($a, $b){
    return strcasecmp(iconv('utf-8', 'ascii//TRANSLIT', $a['name']), iconv('utf-8', 'ascii//TRANSLIT', $b['name']));    
});
print_r($countries);
输出:

Array
(
    [0] => Array
        (
            [name] => Afghanistan
            [code] => AF
        )
    [1] => Array
        (
            [name] => Åland Islands
            [code] => AX
        )
    [2] => Array
        (
            [name] => United Kingdom
            [code] => GB
        )
)