To avoid performing iterated lookups for teamID
values while traversing your input array, it is best practice to generate a lookup array first / separately.
Creating the lookup array is certainly more tedious than applying it. I've commented the temporary array values to help you to understand what is generated at each step. Using relevant variable names and array functions (which improve code comprehension), I think it shouldn't be too hard to follow.
For those that are unable to compare code performance, MarcusKreusch's answer is currently the only other answer that provides the correct results. However, it is doing two scans (within the custom function calls) of the input array on each iteration of the input array. My solution is more direct and efficient because it uses fewer iterated function calls / loops / conditions.
Code: (Demo)
$lookup=array_column($arr,'teamID','teamName'); // var_export($lookup); // ['USA'=>'','Norway'=>'','Germany'=>'','Slovakia'=>'']
$positive_ids=array_filter(array_flip(array_column($arr,'teamName','teamID'))); // var_export($positive_ids); // ['Norway'=>12]
$i=0;
foreach($lookup as $name=>&$id){
if(isset($positive_ids[$name])){
$id=$positive_ids[$name];
}else{
while(in_array(++$i,$positive_ids)); // avoid collisions between existing and new ids
$id=$i;
}
} // var_export($lookup); // ['USA'=>1,'Norway'=>12,'Germany'=>2,'Slovakia'=>3]
foreach($arr as &$row){
$row['teamID']=$lookup[$row['teamName']]; // make id assignments
}
Result: (modified $arr
now contains...)
array(
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> 12,'teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> 12,'teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> 1,'teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> 2,'teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> 3,'teamName' => 'Slovakia', 'playerName'=>'Ivan')
)
I want to clarify that my solution appropriately handles two possible and troublesome input arrays:
Issue: Gaps in incremented ids
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'=>'Ivan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '12','teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'=>'Alexander')
);
Upon close inspection, you will see that the first occurrence of Norway
is without an id. Any method that is looping the array to assign new keys will deem Norway
in need of an incremented id
. Since Norway
comes after USA
(which claims 1
), Norway
's id is given 2
. Then Slovakia
is given 3
. Then the id
for Norway
is overwritten as 12
. Finally, Germany
is given 4
. This leaves gaps in the incrementation.
Issue: Collision between existing and new ids
$arr = array(
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'John'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Peter'),
array('teamID'=> '2','teamName' => 'Norway', 'playerName'=>'Zigmund'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Parker'),
array('teamID'=> '','teamName' => 'Norway', 'playerName'=>'Jan'),
array('teamID'=> '','teamName' => 'USA', 'playerName'=>'Hector'),
array('teamID'=> '','teamName' => 'Germany', 'playerName'=>'Alexander'),
array('teamID'=> '','teamName' => 'Slovakia', 'playerName'=>'Ivan')
);
Without a check for id collisions, the above array will generate two teams with 2
as the id.