Search code examples
phparraysmultidimensional-arrayarray-sum

Combine 2 PHP arrays to create a leaderboard


I have 2 arrays - Dealerships and Scores:

Dealerships

Array(
    [0] => Test Dealership 2
    [1] => Test Dealership
    [2] => Test Dealership
    [3] => Test Dealership 3
    [4] => Test Dealership
)

Scores

Array(
    [0] => 0
    [1] => 427
    [2] => 266
    [3] => 375
    [4] => 180
)

All I am trying to do is create a leaderboard that looks like this:

It needs to combine the scores for matching dealerships.


Dealership Leaderboard

1. Test Dealership - 873
2. Test Dealership 3 - 375
3. Test Dealership 2 - 0


I have mapped the arrays to create this:

Array
(
    [0] => Array
        (
            [0] => Test Dealership 2
            [1] => 0
        )

    [1] => Array
        (
            [0] => Test Dealership
            [1] => 427
        )

    [2] => Array
        (
            [0] => Test Dealership
            [1] => 266
        )

    [3] => Array
        (
            [0] => Test Dealership 3
            [1] => 375
        )

    [4] => Array
        (
            [0] => Test Dealership
            [1] => 180
        )

)

But I'm drawing a blank on how to get to the next stage.


Solution

  • You're probably looking for a function like this:

    function reduce_total_scores($input) {
            $output = array_reduce($input, function ($carry, array $current) {
                    if (!isset($carry[$current[0]])) $carry[$current[0]] = 0;
                    $carry[$current[0]] += $current[1];
                    return $carry;
            }, []);
            arsort($output);
            return $output;
    }
    

    To show it in action:

    <?php
    
    $dealerships = [
            'Test Dealership 2',
            'Test Dealership',
            'Test Dealership',
            'Test Dealership 3',
            'Test Dealership',
    ];
    
    $scores = [
            0,
            427,
            266,
            375,
            180,
    ];
    
    /**
     * Just a function to create the combined array as the poster did.
     */
    function join_array_values(...$arrs) {
            $result = [];
            $l = array_reduce($arrs, function ($carry, array $current) {
                    $l = sizeof($current);
                    return ($carry >= $l) ? $carry : $l;
            }, 0);
            foreach ($arrs as $i => $arr) {
                    $arr = array_values($arr); // only take values
                    for ($j=0; $j<$l; $j++) {
                            $result[$j][$i] = $arr[$j] ?? null;
                    }
            }
            return $result;
    }
    
    /**
     * Reduce the totals of different dealerships
     */
    function reduce_total_scores($input) {
            $output = array_reduce($input, function ($carry, array $current) {
                    if (!isset($carry[$current[0]])) $carry[$current[0]] = 0;
                    $carry[$current[0]] += $current[1];
                    return $carry;
            }, []);
            arsort($output);
            return $output;
    }
    
    $input = join_array_values($dealerships, $scores);
    
    echo "input\n------\n";
    print_r($input);
    
    echo "\nresult\n------\n";
    print_r(reduce_total_scores($input));
    

    Run Result:

    input
    ------
    Array
    (
        [0] => Array
            (
                [0] => Test Dealership 2
                [1] => 0
            )
    
        [1] => Array
            (
                [0] => Test Dealership
                [1] => 427
            )
    
        [2] => Array
            (
                [0] => Test Dealership
                [1] => 266
            )
    
        [3] => Array
            (
                [0] => Test Dealership 3
                [1] => 375
            )
    
        [4] => Array
            (
                [0] => Test Dealership
                [1] => 180
            )
    
    )
    
    output
    ------
    Array
    (
        [Test Dealership] => 873
        [Test Dealership 3] => 375
        [Test Dealership 2] => 0
    )
    

    Should be easy to fashion an output from the assoc array produced by reduce_total_scores().