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

Stark
  • 572
  • 10
  • 24
  • Does this answer your question? [Sort an array by multiple keys in PHP](https://stackoverflow.com/questions/10846221/sort-an-array-by-multiple-keys-in-php) – Jonnix Oct 14 '20 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? – Nick Oct 14 '20 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. – Stark Oct 15 '20 at 00: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)? – Nick Oct 15 '20 at 00:10
  • @Nick the one with the least carb (1). – Stark Oct 15 '20 at 00:13

1 Answers1

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

Nick
  • 138,499
  • 22
  • 57
  • 95