根据比较关联键的多个规则对每行中的元素进行排序

Sort elements in each row based on multiple rules comparing associative keys

我有一个多维数组,想按自定义顺序按键对它的子数组进行排序,其中我有一些固定位置和一些相对位置。

数组如下所示:

$array = [
    [
        "ARRIVAL" => '2022-03-08',
        "INFO" => "TEST",
        "V1_PROZ_WET" => 7,
        "V1_ABS_WET" => 200,
        "V1_PROZ" => 4,
        "V1_ABS" => 150,
        "V2_PROZ_WET" => 10,
        "V2_ABS_WET" => 250,
        "V2_PROZ" => 5,
        "V2_ABS" => 180,
        "BEZ" => "TEST",
        "WET_TOTAL" => 500,
        "DRY_TOTAL" => 300
    ],
    [
        "ARRIVAL" => '2022-03-07',
        "INFO" => "TEST",
        "V1_PROZ_WET" => 7,
        "V1_ABS_WET" => 200,
        "V1_PROZ" => 4,
        "V1_ABS" => 150,
        "V2_PROZ_WET" => 10,
        "V2_ABS_WET" => 250,
        "V2_PROZ" => 5,
        "V2_ABS" => 180,
        "BEZ" => "TEST",
        "WET_TOTAL" => 500,
        "DRY_TOTAL" => 300
    ],
    [
        "ARRIVAL" => '2022-03-06',
        "INFO" => "TEST",
        "V1_PROZ_WET" => 7,
        "V1_ABS_WET" => 200,
        "V1_PROZ" => 4,
        "V1_ABS" => 150,
        "V2_PROZ_WET" => 10,
        "V2_ABS_WET" => 250,
        "V2_PROZ" => 5,
        "V2_ABS" => 180,
        "BEZ" => "TEST",
        "WET_TOTAL" => 500,
        "DRY_TOTAL" => 300
    ],
];

我想按以下顺序排序:

$sortOrder = [
    "INFO",         //fixed pos 1
    "BEZ",          //fixed pos 2
    "WET_TOTAL",    //fixed pos 3
    "DRY_TOTAL",    //fixed pos 4
    "_PROZ",        //all dry percentage values
    "_ABS",         //all dry abs values
    "_PROZ_WET",    //all wet percentage values
    "_ABS_WET"      //all wet abs values
];

子数组的预期输出为:

[
    "INFO" => "TEST",
    "BEZ" => "TEST",
    "WET_TOTAL" => 500,
    "DRY_TOTAL" => 300,
    "V1_PROZ" => 4,
    "V2_PROZ" => 5,
    "V1_ABS" => 150,
    "V2_ABS" => 180,
    "V1_PROZ_WET" => 7,
    "V2_PROZ_WET" => 10,
    "V1_ABS_WET" => 200,
    "V2_ABS_WET" => 250,
    "ARRIVAL" => '2022-03-06'
]

我看到 PHP 的 usort 能够执行自定义排序功能,但我被卡住了,因为我无法获得它 运行.

这个 SO-Answer 给了我一些关于如何对多维数组进行自定义排序的很好的输入,但我需要通过键对它们进行排序并且没有我可以随时查看的“id”键在

这里是一个fiddle的游乐场。

在每一行调用 uksort() 时迭代 modify-by-reference。

使用 Elvis 运算符回退到优先级较低的标准。

如果您的 PHP 版本还没有提供箭头函数,您需要调整脚本以使用 long-handed 函数语法。

如果您的 PHP 版本尚未提供 str_contains(),您需要将这些调用换成 long-winded strpos() !== false 检查。

这种 boolean-based 排序算法可以欺骗不熟悉排序的开发人员。当飞船运算符比较两个布尔值时,它将 false 视为 0,将 true 视为 1。换句话说,如果您使用 ASC 排序,则 false 记录排在 true 记录之前。如果你想要相反的排序方向,那么你交换表达式中 $a$b 的位置。 $b <=> $a表示降序排列。

代码:(Demo)

foreach ($array as &$row) {
    uksort($row, fn($a, $b) => 
        ($b === 'INFO') <=> ($a === 'INFO')
        ?: ($b === 'BEZ') <=> ($a === 'BEZ')
        ?: ($b === 'WET_TOTAL') <=> ($a === 'WET_TOTAL')
        ?: ($b === 'DRY_TOTAL') <=> ($a === 'DRY_TOTAL')
        ?: ($a === 'ARRIVAL') <=> ($b === 'ARRIVAL')
        ?: str_contains($a, '_WET') <=> str_contains($b, '_WET')
        ?: str_contains($b, '_PROZ') <=> str_contains($a, '_PROZ')
        ?: str_contains($b, '_ABS') <=> str_contains($a, '_ABS')
        ?: $a <=> $b
    );
}    
var_export($array);

输出:

array (
  0 => 
  array (
    'INFO' => 'TEST',
    'BEZ' => 'TEST',
    'WET_TOTAL' => 500,
    'DRY_TOTAL' => 300,
    'V1_PROZ' => 4,
    'V2_PROZ' => 5,
    'V1_ABS' => 150,
    'V2_ABS' => 180,
    'V1_PROZ_WET' => 7,
    'V2_PROZ_WET' => 10,
    'V1_ABS_WET' => 200,
    'V2_ABS_WET' => 250,
    'ARRIVAL' => '2022-03-08',
  ),
  1 => 
  array (
    'INFO' => 'TEST',
    'BEZ' => 'TEST',
    'WET_TOTAL' => 500,
    'DRY_TOTAL' => 300,
    'V1_PROZ' => 4,
    'V2_PROZ' => 5,
    'V1_ABS' => 150,
    'V2_ABS' => 180,
    'V1_PROZ_WET' => 7,
    'V2_PROZ_WET' => 10,
    'V1_ABS_WET' => 200,
    'V2_ABS_WET' => 250,
    'ARRIVAL' => '2022-03-07',
  ),
  2 => 
  array (
    'INFO' => 'TEST',
    'BEZ' => 'TEST',
    'WET_TOTAL' => 500,
    'DRY_TOTAL' => 300,
    'V1_PROZ' => 4,
    'V2_PROZ' => 5,
    'V1_ABS' => 150,
    'V2_ABS' => 180,
    'V1_PROZ_WET' => 7,
    'V2_PROZ_WET' => 10,
    'V1_ABS_WET' => 200,
    'V2_ABS_WET' => 250,
    'ARRIVAL' => '2022-03-06',
  ),
)