2

I have 2 arrays that I want to merge based on a key's value in array 1. In the below example, I want the game_modes put into the games_list based on a key (id) in games_list.

Array 1 which is pulled from a table full of games:

$games_list = array(
  0 => array(
    'id' => 23,
    'name' => 'Call of Duty: Modern Warfare 3'
    ),
  2 => array(
    'id' => 1,
    'name' => 'Call of Duty: Black Ops'
    )
  );

Array 2 which is pulled from a table full of game modes:

$game_modes = array(
  0 => array(
    'id' => 1,
    'game_id' => 1,
    'description' => 'Capture the Flag'
    ),
  1 => array(
    'id' => 2,
    'game_id' => 1,
    'description => 'Domination'
    ),

  2 => array(
    'id' => 3,
    'game_id' => 23,
    'description' => 'Kill Confirmed'
    )
  );

I would like the result to be:

$games_list = array(
  0 => array(
    'id' => 23,
    'name' => 'Call of Duty: Modern Warfare 3'
    'modes' => array(
        array(
          'id' => 3,
          'game_id' => 23,
          'description' => 'Kill Confirmed'
          )
        )
    ),
  2 => array(
    'id' => 1,
    'name' => 'Call of Duty: Black Ops'
    'modes'=> array(
      0 => array(
        'id' => 1,
        'game_id' => 1,
        'description' => 'Capture the Flag'
        ),
      1 => array(
        'id' => 2,
        'game_id' => 1,
        'description => 'Domination'
        )
      )
    )
  );

Additional info, the site I'm working on currently has 71 games in its database and each game could have some arbitrary number of game modes.

Now, I could easily do a bunch of for loops and avoid this question all together. As of right now I don't have ton of game modes entered into the database but I keep adding more all the time. Over time doing exponentially more loops all the time will eventually make the page load speed come to a crawl.

I have taken the time to place this data into memcache to make future calls quicker avoiding the loop.

I've never been good with array_map as I don't quite understand how it works or if its even the right route.

4 Answers 4

3

Don't you think query level solution would be better? The lengthy way would be:

// array:  $game_modes;
// array:  $game_lists;

foreach ($game_modes as $gm=>$modes){
   if (isset($modes['game_id'])){
      foreach ($game_lists as $gl=>$lists){
         if ($lists['id'] == $modes['game_id']){
            $game_lists[$gl]['modes'][] = $modes;
            //break;
         }
      }
   }
}

Output Category : Summary

$query = 'SELECT 
                g.id, g.name_name,
                group_concat(gm.description) as descriptions
          FROM games as g
          LEFT JOIN games_modes as gm
               ON g.id = gm.game_id
          GROUP BY g.id';

Result:

  id |  name                     |  descriptions
------------------------------------------------------------
  1  |  Call of Duty: Black Ops  |  Capture the Flag, Domination

Output Category : Detail

$query = 'SELECT 
                g.id, g.name_name,
                gm.id, gm.description
          FROM games as g
          LEFT JOIN games_modes as gm
               ON g.id = gm.game_id
          ORDER BY g.id';

Result:

  id |  name                     |  id   |  description
----- --------------------------- ------- ------------------
  1  |  Call of Duty: Black Ops  |   1   |  Capture the Flag
  1  |  Call of Duty: Black Ops  |   2   |  Domination
Sign up to request clarification or add additional context in comments.

11 Comments

I was thinking about doing it a query way, but then I'd have a bunch of entries for each game based on the number of game modes.
@Jayrox: I still believe, query would be more efficient way. Can you provide relevant table/fields?
games table is just (id, game_name) games_modes table is (id, game_id, description)
Updated my post accordingly. Think this would be the most efficient solution.
ok, ran the query and it gave the results as you described. this may work for my needs. i'll try it out and select this answer.
|
0

Try this to decrease looping

$cachearray = array();
foreach ($game_modes as $gm=>$modes){
  if(array_key_exists($modes['game_id'],$cachearray))
  {
     $cachearray[$modes['game_id']]['modes'][] = $modes;
  }
  else         
     foreach ($games_list as $gl=>$lists){
        if ($lists['id'] == $modes['game_id']){
           $games_list[$gl]['modes'][] = $modes;
           $cachearray[$lists['id']] = &$games_list[$gl];
           break;
        }
     }
}

print_r($games_list);

It will be easier if you have $games_list array like this

$games_list = array(
   23 => array(
     'id' => 23,
     'name' => 'Call of Duty: Modern Warfare 3'
   ),
   1 => array(
     'id' => 1,
     'name' => 'Call of Duty: Black Ops'
   )
);

And will more powerfull by using query

5 Comments

without doing a for loop, is there a way to make a mysql query make the keys named based on their id, for your example?
@Jayrox I don't know where are your array come from. But, if they are from fetching so there is a way. FYI, my example is for your current array situation. But with my $games_list, then you don't need $cachearray in my code.
they are coming from a mysql table. games(id, name) games_modes(id, game_id, description)
@Jayrox Is there any thing like mysql_fetch_array on your code?
i'm using PDO which gives its results in an array
0

If you want to user array map, this code should be possible:

$ids = array_map(function($game) { return $game['id']; }, $games_list);
$id_mapping = array_flip($ids);    

foreach($game_modes as $mode) {
    if (array_key_exists($mode['game_id'], $id_mapping)) {
        $games_list[$id_mapping[$mode['game_id']]]['modes'][] = $mode;
    }
}

But I do not know whether this is faster than the two for loops.

Comments

0

try this:

$mode_map = array();
foreach($game_modes as $mode)
{
    $game_id = $mode['game_id'];
    if(!isset($mode_map[$game_id]))
    {
        $mode_map[$game_id] = array();
    }

    $mode_map[$game_id][] = $mode;
}

foreach($games_list as &$game)
{
    $game_id = $game['id'];
    if(isset($mode_map[$game_id]))
    {
        $game['modes'] = $mode_map[$game_id];
    }
}

print_r($games_list);

result:

Array
(
    [0] => Array
        (
            [id] => 23
            [name] => Call of Duty: Modern Warfare 3
            [modes] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [game_id] => 23
                            [description] => Kill Confirmed
                        )

                )

        )

    [2] => Array
        (
            [id] => 1
            [name] => Call of Duty: Black Ops
            [modes] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [game_id] => 1
                            [description] => Capture the Flag
                        )

                    [1] => Array
                        (
                            [id] => 2
                            [game_id] => 1
                            [description] => Domination
                        )

                )

        )

)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.