0

I'm trying to sort an array prioritizing the closest macros value to the optimal values, i.e the element best matching the criteria is id of 200 (but is sorted), looks like all the "points" goes to the prev element instead.

function sorter(array $array, $optimal, $minMax){
    usort($array, function($prev, $curr) use($optimal, $minMax){
    
    $points = ['prev' => 0, 'curr' => 0];

    foreach($curr['macros'] as $macro => $value){                       
        if($value > $minMax[$macro]["minimum"] && $value <= $optimal[$macro]){
            if($macro === "protein"){
                $points['curr'] += 2;
            }
            
            if($macro === "carb" && $value < $prev["macros"][$macro]){
                $points['curr'] += 1;
            }
            
            ++$points['curr'];  
        } else {
            ++$points['prev'];
        }
    }
    
    if($points['prev'] === $points['curr']) return 0;

    return $points['prev'] < $points['curr'] ? -1 : 1;
});

return $array;
}

The protein has a higher priority, with carbs coming second.

http://sandbox.onlinephpfunctions.com/code/77fc35f2fb0b60de9271f7e934a5a8a4aa3b25a3

5
  • Does this answer your question? Sort an array by multiple keys in PHP Commented Oct 14, 2020 at 23:24
  • Your sorting criteria is unclear. Are you saying that the closest element to optimal for protein should be sorted first, and if two elements are equal in that measure, the closest for carbs should be sorted first? Commented Oct 14, 2020 at 23:43
  • @Nick Basically all elements closest to the optimal value should be sorted first, but if the current element has protein closer to 25.93 and contains less carbs then the previous element, it should be prioritized. Commented Oct 15, 2020 at 0:07
  • So if two elements both had protein of 24 and one had carb of 1 and the other had carb of 2, which should be sorted first, the one with least carb (1) or the one with carb closest to optimal (2)? Commented Oct 15, 2020 at 0:10
  • @Nick the one with the least carb (1). Commented Oct 15, 2020 at 0:13

1 Answer 1

1

From your description, it sounds like you want to sort by the closeness of the protein value to optimal, breaking ties by using the lowest carb value. This can be done by taking the abs of the difference between actual and optimal protein values, and if equal, comparing the carb values to find the least:

function sorter(array $array, $optimal, $minMax){
    usort($array, function ($a, $b) use ($optimal, $minMax) {
        // check closeness of protein to optimal
        $apo = abs($a['macros']['protein'] - $optimal['protein']);
        $bpo = abs($b['macros']['protein'] - $optimal['protein']);
        // if not equally close, return the closest
        if ($apo != $bpo) return $apo <=> $bpo;
        // same protein difference to optimal, return the one with least carbs
        return $a['macros']['carb'] <=> $b['macros']['carb'];
    });
    return $array;
}

For your sample data this returns:

Array
(
    [0] => Array
        (
            [id] => 200
            [macros] => Array
                (
                    [calorie] => 443.21
                    [fat] => 35.95
                    [carb] => 3.86
                    [protein] => 24.3
                )
        )
    [1] => Array
        (
            [id] => 3
            [macros] => Array
                (
                    [calorie] => 472.07
                    [fat] => 38.4
                    [carb] => 9.46
                    [protein] => 18.25
                )
        )
    [2] => Array
        (
            [id] => 19
            [macros] => Array
                (
                    [calorie] => 455.22
                    [fat] => 42.08
                    [carb] => 5.25
                    [protein] => 15.81
                )
        )
    [3] => Array
        (
            [id] => 18
            [macros] => Array
                (
                    [calorie] => 457.73
                    [fat] => 41.92
                    [carb] => 5.61
                    [protein] => 10.94
                )
        )
    [4] => Array
        (
            [id] => 9
            [macros] => Array
                (
                    [calorie] => 445.37
                    [fat] => 41.15
                    [carb] => 9.25
                    [protein] => 10.13
                )
        )
    [5] => Array
        (
            [id] => 1
            [macros] => Array
                (
                    [calorie] => 487.98
                    [fat] => 48.79
                    [carb] => 7.35
                    [protein] => 8.06
                )
        )
)

Demo on 3v4l.org

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.