简体   繁体   中英

PHP Arrray sorting with usort ABC values

Please help with following sample code.

I am trying to sort such that 'B' goes last in the array.

I have tried quite a few ways. originally I was working with uasort. However to debug, i have simplified it to usort.

<?php
$array = json_decode('[
    {
        "id": "222",
        "name": "A",
        "shouldgolast": "N"
    },
    {
        "id": "261",
        "name": "B",
        "shouldgolast": "Y"
    },
    {
        "id": "262",
        "name": "C",
        "shouldgolast": "N"
    }
]', true);
usort($array, "sortF");
foreach ($array as $details) {
    echo $details["name"]."\n";
}
function sortF($a, $b)
{
    if($a['shouldgolast'] == "Y"){
        return 1;
    }else if($b['shouldgolast'] == "Y"){
        return 1;
    }
    return 0;
}
?>

Output for above is

B
A
C

I expect B to be last.

Test link: https://www.tehplayground.com/DzqhjFq6lK9Zq9Ue

Also tried by return -1 instead of 1 (that bring B to second position) Test link 2: https://www.tehplayground.com/ea51PWdFfkAupEsd

The usort function receive, as a 2nd argument, a callable that should work as a comparator. A comparator generally works in this way:

  • return 1 -> the first is greater than the second element
  • return -1 -> the 2nd is greater than the first element
  • return 0 -> the two element are same

You have to correct your comparator function in this way

function sortF($a, $b)
{
    if($a['shouldgolast'] == "Y"){
        return 1;
    }else if($b['shouldgolast'] == "Y"){
        return -1;
    }
    return 0;
}

If you just want to move all the shouldgolast s to the end, you don't actually need to compare $a to $b , and you don't even need to return zero or -1. The only logic the comparison expression really needs is "If $a should go last, move it down."

usort($array, fn($a) => $a['shouldgolast'] === 'Y');

The thing is you had else if statement that return 1 , I don't think the logic is right for this case, it should return the appropriate value based on condition that can be applied to your case, Your code should look like this:

<?php
$array = json_decode('[
    {
        "shouldgolast": "222",
        "name": "A",
        "shouldgolast": "N"
    },
    {
        "id": "261",
        "name": "B",
        "shouldgolast": "Y"
    },
    {
        "id": "262",
        "name": "C",
        "shouldgolast": "N"
    }
]', true);

usort($array, "sortF");

foreach ($array as $details) {
    echo $details["name"]."\n";
}

function sortF($a, $b)
{
    if($a['shouldgolast'] == "Y"){
        return 1;
    }

    if($b['shouldgolast'] == "Y"){
        return -1;
    }

    return 0;
}
?>

You don't need to sort the values.

Approach #1:

You can just make use of a pointer to move all arrays with shouldgolast as Y to the right. This is similar toDutch national flag algorithm where we group items together.

Snippet:

$yes_ptr = count($array) - 1;

for($i = count($array) - 1; $i >= 0; -- $i){
    if($array[$i]['shouldgolast'] == 'Y'){
        $temp = $array[$yes_ptr];
        $array[$yes_ptr--] = $array[$i];
        $array[$i] = $temp;
    }
}

Demo: https://3v4l.org/KHFQr

In the above approach, we just keep a yes_ptr pointer which indicates the current position where any new upcoming Y should be inserted at. Note that this will successfully group all N first and all Y later. However, this might change the internal ordering of elements with value N .

Approach #2:

If you want a stable grouping, meaning preserving the order of all N elements and Y elements, you can simply collect them in 2 different arrays and do an array_merge .

Snippet:

$no_array = [];
$yes_array = [];

foreach($array as $value){
    if($value['shouldgolast'] == 'N'){
        $no_array[] = $value;
    }else{
        $yes_array[] = $value;
    }
}

print_r(array_merge($no_array,$yes_array));

Demo: https://3v4l.org/Se1qd

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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