1

As shown below I have a multi-dimensional array with an associative array in the third level that I am trying to manipulate based on gamesCount. I want to generate a new array of items with the highest gamesCount in each sport. Is there an efficient way to this without going overkill?

EDIT: It could be n number of sports hence the goal is to find the max number for gameCounts for each sport.

Initial array:

$array = [
    [
        ["sport" => "soccer", "gamesCount" => 5, "gamesId" => 1],
        ["sport" => "soccer", "gamesCount" => 3, "gamesId" => 2],
        ["sport" => "soccer", "gamesCount" => 10, "gamesId" => 3],
        ["sport" => "soccer", "gamesCount" => 10, "gamesId" => 4],
    ],
    [
        ["sport" => "basketball", "gamesCount" => 1, "gamesId" => 5],
        ["sport" => "basketball", "gamesCount" => 3, "gamesId" => 6],
        ["sport" => "basketball", "gamesCount" => 3, "gamesId" => 7],
        ["sport" => "basketball", "gamesCount" => 8, "gamesId" => 8],
    ]
];

Desired Result:

array(3) {
      [0]=>
      array(3) {
        ["sport"]=>
        string(6) "soccer"
        ["gamesCount"]=>
        int(10)
        ["gamesId"]=>
        int(3)
      }
      [1]=>
      array(3) {
        ["sport"]=>
        string(6) "soccer"
        ["gamesCount"]=>
        int(10)
        ["gamesId"]=>
        int(4)
      }
      [2]=>
      array(3) {
        ["sport"]=>
        string(10) "basketball"
        ["gamesCount"]=>
        int(5)
        ["gamesId"]=>
        int(8)
      }
}
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
MaryCoding
  • 624
  • 1
  • 9
  • 31

2 Answers2

1

try this, check the live demo

$result = [];
foreach($array as $v)
{
$max = max(array_column($v, 'gamesCount'));
    $result = array_merge($result, array_filter($v, function($value)use($max){return $value['gamesCount'] == $max;}));
}
var_dump($result);
LF00
  • 27,015
  • 29
  • 156
  • 295
  • I am getting an error: `Warning: max(): Array must contain at least one element` for this line `return max(array_column($v, 'gameCount'));`. I double checked and `$array` does contain an array an its elements. – MaryCoding May 19 '17 at 06:23
  • @MaryCoding there is a error, it should be gamesCount in the code. – LF00 May 19 '17 at 06:30
  • It yields an empty array. Check this [GIST](https://gist.github.com/MaryCoding/d0b8fa3942bde4121578b72518169856) – MaryCoding May 19 '17 at 06:33
  • @KrisRoofe No Kris, check the edit history. Same structure. Now she is using my php-ready variable instead of the print_r output that she first posted. The sports were always in two separate subarrays. – mickmackusa May 19 '17 at 06:40
  • @mickmackusa sorry, I miss use a function. check it now – LF00 May 19 '17 at 06:45
  • It is not finding the max for each sport. I only see the soccer max but what about the basketball? – MaryCoding May 19 '17 at 06:54
  • @MaryCoding check it now – LF00 May 19 '17 at 06:58
1

Input:

$array=[
    [
        ["sport"=>"soccer","gamesCount"=>5,"gamesId"=>1],
        ["sport"=>"soccer","gamesCount"=>3,"gamesId"=>2],
        ["sport"=>"soccer","gamesCount"=>10,"gamesId"=>3],
        ["sport"=>"soccer","gamesCount"=>10,"gamesId"=>4]
    ],
    [
        ["sport"=>"basketball","gamesCount"=>1,"gamesId"=>5],
        ["sport"=>"basketball","gamesCount"=>3,"gamesId"=>6],
        ["sport"=>"basketball","gamesCount"=>3,"gamesId"=>7],
        ["sport"=>"basketball","gamesCount"=>8,"gamesId"=>8]
    ]
];

Method #1 "The easiest to read version with two loops" (Demo)

foreach($array as $sport_array){
    $most_in_sport=max(array_column($sport_array,'gamesCount'));  // get highest gamesCount in sport's subarray      
    foreach($sport_array as $sport_row){
        if($sport_row['gamesCount']==$most_in_sport){  // only keep a sport's subarray (row) if its gamesCount is the highest in the sport
            $most_per_sport[]=$sport_row;
        }
    }
}
var_export($most_per_sport);

Method #2: "The obscenely convoluted variadic one-liner" php minimum version: 5.6 (For those who wish who do not fear the one-liner apocalypse -- reference: 1st comment @ https://stackoverflow.com/a/43950486/2943403.) (Demo)

var_export(array_merge(...array_map(function($sport_array){$most_in_sport=max(array_column($sport_array,'gamesCount')); return array_filter($sport_array,function($sport_row)use($most_in_sport){return $sport_row['gamesCount']==$most_in_sport;});},$array)));

Output:

array (
  0 => 
  array (
    'sport' => 'soccer',
    'gamesCount' => 10,
    'gamesId' => 3,
  ),
  1 => 
  array (
    'sport' => 'soccer',
    'gamesCount' => 10,
    'gamesId' => 4,
  ),
  2 => 
  array (
    'sport' => 'basketball',
    'gamesCount' => 8,
    'gamesId' => 8,
  ),
)

Deciding which method to use is up to each individual programmer. The first method will be most efficient and IMO easiest to comprehend. The second will generate less global variables and require less lines of code. If you are trying to avoid "over-kill" Method #1 cannot be beaten.

Community
  • 1
  • 1
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • This only handles two arrays but thing is that it could be `n` number of arrays. E.g. `basketball`, `soccer`, `baseball`, etc. – MaryCoding May 19 '17 at 06:26
  • @MaryCoding What do you think now? I have provided two methods to suit a range of php versions. – mickmackusa May 19 '17 at 06:38
  • This got me closer to a result but this is line is hardcoded `$top3 = array_slice($array, 0, 3); // extract the top 3 subarrays`. It could be `n` number of sports hence `n` number of `max` for `gameCounts`. Specially if there are the same value for some. – MaryCoding May 19 '17 at 06:52
  • @MaryCoding You never said in your question where to draw the line, so I replicated your desired result. You can change it to whatever you like. – mickmackusa May 19 '17 at 06:53
  • You are correct. My apologies. I will update the question. Thanks. – MaryCoding May 19 '17 at 06:55