优先级为

时间:2018-05-24 13:47:43

标签: php arrays sorting offset

我需要一种按优先级排序项目数组的方法。

这是我到目前为止所做的工作:

function arraySortPriority(array &$array, $offset, array $priorities)
{
    uasort($array, function ($a, $b) use ($offset, $priorities) {
        if (!isset($a[$offset])) {
            $a[$offset] = null;
        }
        if (!isset($b[$offset])) {
            $b[$offset] = null;
        }
        if ($a[$offset] == $b[$offset]) {
            return 0;
        }
        $aPriority = isset($priorities[$a[$offset]])
            ? $priorities[$a[$offset]]
            : null;
        $bPriority = isset($priorities[$b[$offset]])
            ? $priorities[$b[$offset]]
            : null;
        return $aPriority > $bPriority ? -1 : 1;
    });
}

// an array to sort
$array = [
    ['type' => 'A'],
    ['type' => 'A'],
    ['type' => 'B'],
    ['type' => 'B'],
    ['type' => 'C'],
    ['type' => 'C'],
    ['type' => 'D'],
    ['type' => 'D'],
    ['type' => 'E'],
    ['type' => 'E'],
    ['type' => 'F'],
    ['type' => 'F'],
    ['type' => 'G'],
    ['type' => 'G'],
    ['type' => 'H'],
    ['type' => 'H'],
    ['type' => 'Foo'],
    ['type' => 'Foo'],
    ['type' => 'Bar'],
    ['type' => 'Bar'],
    [0 => 'no type should be last'],
    [0 => 'no type should be last'],
];
// shuffle the array
shuffle($array);
// set priorities
$priorities = [
    'A' => 8,
    'B' => 7,
    'C' => 6,
    'D' => 5,
    'E' => 4,
    'F' => 3,
    'G' => 2,
    'H' => 1,
];
// call
arraySortPriority($array, 'type', $priorities);
// test output
foreach ($array as $item) {
    if (isset($item['type'])) {
        echo "{$item['type']}\r\n";
    } else {
        $values = array_values($item);
        echo reset($values) . PHP_EOL;
    }
}

预期:

A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
Foo
Foo
Bar
Bar
no type should be last
no type should be last

实际

A
A
B
B
C
C
D
D
E
E
F
F
G
G
H
H
no type should be last   <-- should be at bottom
no type should be last   <-- should be at bottom
Bar
Bar
Foo
Foo

问题是,未提供$offset的项目应始终排在最底层。

这意味着no type should be last的排序应始终低于FooBar

我该怎么做?

4 个答案:

答案 0 :(得分:2)

<?php 

// an array to sort
$array = [
    ['type' => 'A'],
    ['type' => 'A'],
    ['type' => 'B'],
    ['type' => 'B'],
    ['type' => 'C'],
    ['type' => 'C'],
    ['type' => 'D'],
    ['type' => 'D'],
    ['type' => 'E'],
    ['type' => 'E'],
    ['type' => 'F'],
    ['type' => 'F'],
    ['type' => 'G'],
    ['type' => 'G'],
    ['type' => 'H'],
    ['type' => 'H'],
    ['type' => 'Foo'],
    ['type' => 'Foo'],
    ['type' => 'Bar'],
    ['type' => 'Bar'],
    [0 => 'no type should be last'],
    [0 => 'no type should be last'],
];
// shuffle the array
shuffle($array);
// set priorities
$priorities = [
    'A' => 8,
    'B' => 7,
    'C' => 6,
    'D' => 5,
    'E' => 4,
    'F' => 3,
    'G' => 2,
    'H' => 1,
];

uasort($array,function($a,$b) use ($priorities){
        if(!isset($a['type'])){
            if(!isset($b['type'])) return -1;
            return 1;
        }else if(!isset($b['type'])){
            return -1;
        }

        if(isset($priorities[$a['type']])){
            if(!isset($priorities[$b['type']])) return -1;

            if($priorities[$a['type']] > $priorities[$b['type']]) return -1;
            else if($priorities[$a['type']] < $priorities[$b['type']]) return 1;

        }else if(isset($priorities[$b['type']])){
            return 1;           
        }

        return 0;
});

echo "<pre>";
print_r($array);

<强>输出

Array
(
    [21] => Array
        (
            [type] => A
        )

    [8] => Array
        (
            [type] => A
        )

    [18] => Array
        (
            [type] => B
        )

    [20] => Array
        (
            [type] => B
        )

    [6] => Array
        (
            [type] => C
        )

    [16] => Array
        (
            [type] => C
        )

    [11] => Array
        (
            [type] => D
        )

    [1] => Array
        (
            [type] => D
        )

    [7] => Array
        (
            [type] => E
        )

    [17] => Array
        (
            [type] => E
        )

    [13] => Array
        (
            [type] => F
        )

    [5] => Array
        (
            [type] => F
        )

    [15] => Array
        (
            [type] => G
        )

    [9] => Array
        (
            [type] => G
        )

    [4] => Array
        (
            [type] => H
        )

    [0] => Array
        (
            [type] => H
        )

    [19] => Array
        (
            [type] => Bar
        )

    [10] => Array
        (
            [type] => Foo
        )

    [14] => Array
        (
            [type] => Bar
        )

    [12] => Array
        (
            [type] => Foo
        )

    [2] => Array
        (
            [0] => no type should be last
        )

    [3] => Array
        (
            [0] => no type should be last
        )

)

答案 1 :(得分:1)

我决定使用@ vivek_23(编辑固定)解决方案。

我编辑了不必要的else,如果f.e.将返回值更改为零。两个偏移都未设置。

如果a和b缺少偏移或没有优先级,则该函数应返回零imo。

工作代码:

uasort($array, function ($a, $b) use ($offset, $priorities) {
    if (!isset($a[$offset])) {
        return !isset($b[$offset])
            ? 0
            : 1; // down
    } elseif (!isset($b[$offset])) {
        return -1; // up
    }
    if (isset($priorities[$a[$offset]])) {
        if (!isset($priorities[$b[$offset]])) {
            return -1; // up
        }
        return $priorities[$a[$offset]] > $priorities[$b[$offset]]
            ? -1 // up
            : 1; // down
    }
    return isset($priorities[$b[$offset]])
        ? 1 // down
        : 0;
});

这允许我使用否定优先级,浮点优先级,并且我不会覆盖优先级(请参阅-99999999 @Eddie解决方案)。

测试

// expect A, A, B, B, C, C, ... "no type ..." at bottom
$priorities = [
    'A' => 8,
    'B' => 7,
    'C' => 6,
    'D' => 5,
    'E' => 4,
    'F' => 3,
    'G' => 2,
    'H' => 1,
];

// expect "no type ..." at bottom, ..., C, C, B, B, A, A
$priorities = [
    'A' => -8,
    'B' => -7,
    'C' => -6,
    'D' => -5,
    'E' => -4,
    'F' => -3,
    'G' => -2,
    'H' => -1,
];

// expect B, B, A, A, C, C, ... "no type ..." at bottom
$priorities = [
    'A' => 6.5,
    'B' => 7,
    'C' => 6,
    'D' => 5,
    'E' => 4,
    'F' => 3,
    'G' => 2,
    'H' => 1,
];

// expect "no type ..." at bottom, ..., C, C, A, A, B, B
$priorities = [
    'A' => -6.5,
    'B' => -7,
    'C' => -6,
    'D' => -5,
    'E' => -4,
    'F' => -3,
    'G' => -2,
    'H' => -1,
];

谢谢@ vivek_23 :)

答案 2 :(得分:0)

您没有处理两个优先级相同的情况。

解决方案1 ​​

只需在三元组之前将以下内容添加到您的函数中:

if ($aPriority == $bPriority)
    return 0;

所以看起来应该是这样的:

uasort($array, function ($a, $b) use ($offset, $priorities) {
    if (!isset($a[$offset])) {
        $a[$offset] = null;
    }
    if (!isset($b[$offset])) {
        $b[$offset] = null;
    }
    if ($a[$offset] == $b[$offset]) {
        return 0;
    }

    $aPriority = isset($priorities[$a[$offset]])
        ? $priorities[$a[$offset]]
        : null;
    $bPriority = isset($priorities[$b[$offset]])
        ? $priorities[$b[$offset]]
        : null;

    if ($aPriority == $bPriority)
        return 0;

    return $aPriority > $bPriority ? -1 : 1;
});

否则,您只是假设$ aPriority小于$ bPriority,如果它不是更大但是它可以相等。

解决方案2

在没有额外情况的情况下实现它的另一种方法是,如果未设置优先级,则将优先级设置为0而不是null

$aPriority = isset($priorities[$a[$offset]])
    ? $priorities[$a[$offset]]
    : 0;
$bPriority = isset($priorities[$b[$offset]])
    ? $priorities[$b[$offset]]
    : 0;

然后返回减法:

return $bPriority - $aPriority;

所以它看起来像这样:

uasort($array, function ($a, $b) use ($offset, $priorities) {
    if (!isset($a[$offset])) {
        $a[$offset] = null;
    }
    if (!isset($b[$offset])) {
        $b[$offset] = null;
    }
    if ($a[$offset] == $b[$offset]) {
        return 0;
    }

    $aPriority = isset($priorities[$a[$offset]])
        ? $priorities[$a[$offset]]
        : 0;
    $bPriority = isset($priorities[$b[$offset]])
        ? $priorities[$b[$offset]]
        : 0;

    return $bPriority - $aPriority;
});

答案 3 :(得分:0)

您有3个逻辑规则进行排序。太空飞船的操作员提供了一种非常清晰简洁的语法,而没有混乱的条件块。

只需在三向比较运算符(<=>)的两侧都写入相应的元素,就会从左到右遵守规则。当$b是第一个/顶部/左侧数组时,则应用DESC顺序;相反,第一/顶部/左侧数组中的$a等同于ASC排序。

  1. 按目标列DESC的存在进行排序
  2. 然后打破#1关系,按优先级值DESC排序
  3. 然后打破#2关系,按目标列值ASC排序

代码:(Demo

function arraySortPriority(array &$array, $column, array $priorities):void
{
    usort($array, function($a, $b) use ($column, $priorities) {
        $aFocus = $a[$column] ?? null;
        $bFocus = $b[$column] ?? null;
        return [array_key_exists($column, $b), $priorities[$bFocus] ?? 0, $aFocus]
               <=>
               [array_key_exists($column, $a), $priorities[$aFocus] ?? 0, $bFocus];
    });
}

arraySortPriority($array, 'type', $priorities);
var_export($array)

如果您的$array永远不会包含null值,则可以进一步完善此代码段,使其在usort()范围内不包含任何函数调用。 < / p>