I've got a class: Game which has values.
I've got two arrays with Game instances. Now I need to compare those two arrays for identical values in the game instance.
The game class has the attributes: homeId visitingId
Now I need to check for identical values in both arrays (they are large, 100+ game instances)
What I do is:
foreach ($games1 as $game1) {
foreach ($games2 as $game2) {
if ( ($game1->getHomeId() == $game2->getHomeId()) && ($game1->getVisitingId() == $game2->getVisitingId())) {
//Games are the same
}
}
}
This takes ages, is there a way to do it quicker?
I've got it running but it's dirty I think.
At first I store the instances in a hashtable, the hash is made out of the visitorId and the homeId.
Then I create an hash of the visitorId and homeId of the other games array.
Then I retrieve the instance by using $table[$hash].
The arrays I used to have aren't the same in lenght, so this works. I don't know if it's too dirty to post here but it works :P
foreach($pGames as $pGame) {
$hash = $pGame->getHomeId() . '-' . $pGame->getVisitingId();
$table[$hash] = $pGame;
}
foreach($games as $game) {
$hash = $game->getHomeId() . '-' . $game->getVisitingId();
$pGame = $table[$hash];
if($pGame instanceof Game) {
//use the instance
}
}
You're doing a lot of redundant calculations. Use a for
loop instead of a foreach
loop and start at where you left off, instead of at the beginning:
$games1_count = count($games1);
$games2_count = count($games2);
for($i=0; $i < $games1_count; $i++) {
$game1 = $games1[$i];
for($j=$i; $j < $games2_count; $j++) {
$game2 = $games2[$j];
if (($game1->getHomeId == $game2->getHomeId()) && $game1->getVisitingId == $game2->getVisitingId()) {
//Games are the same
}
}
}
This should provide a pretty significant speed boost. It won't decrease the order of the problem, but it will cut your calculations in half.
EDIT
You should also look into some sort of indexing. When you populate $game1
, for instance, create an array that stores the games by value:
$game_index = array(
"home_id"=array(
"id1"=>$reference_to_game_with_id1,
"id2"=>$reference_to_game_with_id2
),
"visiting_id"=array(
"id1"=>$reference_to_game_with_visiting_id1,
"id2"=>$reference_to_game_with_visiting_id2
)
);
How about using the array_diff function in some way which compares two arrays. http://php.net/manual/en/function.array-diff.php
Your current solution has complexity of O(n*n). it is possible to get it down to O(nlogn). For this you'll have to sort both arrays and then compare them. I would do something like:
$t1=array();
foreach ($games1 as $key=>$game1) {
$t1[$key]=$game1->getHomeId;
}
asort($t1);
$t2=array();
foreach ($games2 as $key=>$game2) {
$t2[$key]=$game2->getHomeId();
}
asort($t2);
$el1=each($t1);
$el2=each($t2);
do{
if ($el1['value']<$el2['value'])
$el1=each($t1);
elseif ($el1['value']>$el2['value'])
$el2=each($t2);
elseif($games1[$el1['key']]->getVisitingId == $games2[$el2['key']]->getVisitingId())
//game are the same
}while($el1 !== false && $el2 !== false)
this produces considerable overhead, so on small amount of data it will work slower. However the more data are in the arrays, the more efficient this algorithm will be.