简体   繁体   English

使用升序、降序、常规、数字和自然排序的组合按多列对关联数组 arrays 进行排序

[英]Sort an array of associative arrays by multiple columns using a combination of ascending, descending, regular, numeric, and natural sorting

Is it possible to sort a multidimensional array by multiple columns using natural sort in PHP?是否可以在 PHP 中使用自然排序按多列对多维数组进行排序? Here is an example.这是一个例子。 Suppose I have a 2D array of data, eg,假设我有一个二维数据数组,例如,

$array[1]['Name'] = 'John';
$array[1]['Age'] = '20';
$array[1]['Code'] = 'ABC 12';

$array[2]['Name'] = 'John';
$array[2]['Age'] = '21';
$array[2]['Code'] = 'ABC 1';

$array[3]['Name'] = 'Mary';
$array[3]['Age'] = '20';
$array[3]['Code'] = 'ABC 10';

I want to sort this array by name (ASC), then by age (DESC), and by code (ASC), all will be sorted naturally.我想按名称 (ASC)、年龄 (DESC) 和代码 (ASC) 对这个数组进行排序,所有这些都会自然排序。 Basically that will be array_multisort with natural sort.基本上这将是具有自然排序的 array_multisort。

I found many solutions about this topic on the web. Unfortunately, they only support sorting by one column, not multiple column.我在web上找到了很多关于这个问题的解决方案,可惜只支持一列排序,不支持多列排序。

I think you have to implement a custom comparison function for this behavior: 我认为您必须为此行为实现自定义比较函数:

function myCmp($a, $b) {
 $nameCmp = strnatcasecmp($a['Name'], $b['Name']);
 $ageCmp = strnatcasecmp($a['Age'], $b['Age']);
 $codeCmp = strnatcasecmp($a['Code'], $b['Code']);

 if ($nameCmp != 0) // Names are not equal
   return($nameCmp);

 // Names are equal, let's compare age

 if ($ageCmp != 0) // Age is not equal
   return($ageCmp * -1); // Invert it since you want DESC

 // Ages are equal, we don't need to compare code, just return the comparison result
   return($codeCmp);
}

Then you can call usort($array, 'myCmp'); 然后你可以调用usort($array, 'myCmp'); and should get the desired sorting 并应得到所需的排序

如果您使用的是PHP 5.4或更高版本,则可以将array_multisortSORT_NATURAL标志一起使用。

Only one of the three sorting rules actually requires natural sorting.三个排序规则中只有一个实际上需要自然排序。 In fact, if you use PHP's 3-way comparison operator ( <=> ), then it will automatically compare numeric strings as numeric values.事实上,如果您使用 PHP 的 3 路比较运算符 ( <=> ),那么它会自动将数字字符串作为数值进行比较。 Only the third rule needs natural sorting to be explicitly declared because it demands the comparison of alphanumeric strings.只有第三条规则需要显式声明自然排序,因为它需要比较字母数字字符串。

Code: ( Demo )代码:(演示

$array = [
    1 => ['Name' => 'John', 'Age' => '20', 'Code' => 'ABC 12'],
    2 => ['Name' => 'John', 'Age' => '21', 'Code' => 'ABC 1'],
    3 => ['Name' => 'Mary', 'Age' => '20', 'Code' => 'ABC 10'],
    4 => ['Name' => 'John', 'Age' => '20', 'Code' => 'ABC 1'],
    5 => ['Name' => 'John', 'Age' => '20', 'Code' => 'ABC 100'],
    6 => ['Name' => 'John', 'Age' => '20', 'Code' => 'ABC 2'],

];

uasort(
    $array,
    fn($a, $b) =>
        [$a['Name'], $b['Age']] <=> [$b['Name'], $a['Age']] // name (ASC) then by age (DESC)
        ?: strnatcasecmp($a['Code'], $b['Code']) // then by code (ASC / naturally)
);
var_export($array);

Output:输出:

array (
  2 => 
  array (
    'Name' => 'John',
    'Age' => '21',
    'Code' => 'ABC 1',
  ),
  4 => 
  array (
    'Name' => 'John',
    'Age' => '20',
    'Code' => 'ABC 1',
  ),
  6 => 
  array (
    'Name' => 'John',
    'Age' => '20',
    'Code' => 'ABC 2',
  ),
  1 => 
  array (
    'Name' => 'John',
    'Age' => '20',
    'Code' => 'ABC 12',
  ),
  5 => 
  array (
    'Name' => 'John',
    'Age' => '20',
    'Code' => 'ABC 100',
  ),
  3 => 
  array (
    'Name' => 'Mary',
    'Age' => '20',
    'Code' => 'ABC 10',
  ),
)

Note the the first level keys are preserved in the output because uasort() is used.请注意,第一级键保留在输出中,因为使用了uasort() Because the input array is not indexed, I am assuming that the keys are ids or something otherwise important.因为输入数组没有索引,我假设键是 id 或其他重要的东西。


If you are comfortable with reindexing the parent level keys, then array_multisort() can be used after generating arrays of columnar data.如果您对重新索引父级键感到满意,则可以在生成列数据数组后使用array_multisort() ( Demo ) 演示

foreach ($array as ['Name' => $names[], 'Age' => $ages[], 'Code' => $codes[]]);

array_multisort(
    $names,        // ASC, REGULAR
    $ages,         // DESC, NUMERIC
    SORT_DESC,
    SORT_NUMERIC,
    $codes,        // ASC, NATURAL
    SORT_ASC,
    SORT_NATURAL,
    $array         // the array to be affected
);
var_export($array);

This code would do the trick: 这段代码可以解决这个问题:

// Your original data stored in $array
$array[1]['Name'] = 'John';
$array[1]['Age'] = '20';
$array[1]['Code'] = 'ABC 12';

$array[2]['Name'] = 'John';
$array[2]['Age'] = '21';
$array[2]['Code'] = 'ABC 1';

$array[3]['Name'] = 'Mary';
$array[3]['Age'] = '20';
$array[3]['Code'] = 'ABC 10';

// Since array_multisort() needs arrays of columns we need to 
// transform it and preserve he keys
foreach ($array as $key => $row) {
    $names[$key] = $row['Name'];
    $ages[$key] = $row['Age'];
    $codes[$key] = $row['Code'];
}

// Sort it according to your criterias
array_multisort($names, SORT_ASC, $ages, SORT_DESC, $codes, SORT_ASC, $array);

// $array now contains your sorted array.

Link to codepad: http://codepad.org/tr83Wt5J 链接到键盘: http//codepad.org/tr83Wt5J

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

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