I wrote a few lines of code in PHP to rename duplicate values in an array (with some inspiration from here).
Basically, I go through the original array ($headers[]), while using the keys of another array ($header_test[]) to keep track of duplicates. If there is a duplicate, I change the value of that element in $headers[].
But the weird thing is that I was not getting the right results by passing by reference in the foreach. I had to actually set the values by using the full $array_name[$key] = $new_value format. Why is that?
(Spoiler alert: VolkerK’s answer is correct – need to unset $header (the foreach “$value” variable) and then it works.)
Here:
Using this input:
$headers = array('Abc 123 ghi',
'dangdarn',
'oops32',
'poss dup',
'poss dup',
'pos _s_ dup',
'bad chars\'& 3% 9'
);
Then applying this custom function which I don’t think would affect the problem at hand:
function mysql_clean_string($string) {
//remove non alnum characters
$string = preg_replace("/[^a-zA-Z0-9\s]/", "_", $string);
// replace 1+ spaces or 1+ '_' with a single '_'
$string = preg_replace("/[ _]+/", "_", $string);
$string = trim($string,'_');
if(strlen($string) > 20) {
$string = substr_replace($string,'',strpos($string,'_',20));
}
$string = strtolower($string);
return $string;
}
array_walk($headers,'mysql_clean_string'); // limit headers to alnum chars
Passing the array values by reference doesn’t work right (see below for var_dump()):
$header_test = array();
foreach($headers as &$header) { //passing by reference
$temp = $header;
if(array_key_exists($temp,$header_test)) {
**$header = $header . '_' . $header_test[$header];**
$header_test[$temp]++;
unset($temp);
} else {
$header_test[$temp] = 1;
}
}
//here is the solution VolkerK suggested and it works:
unset($header);
Here are the var_dump outputs with incorrect results (duplicate values and notice “&” at headers[6], and missing last value):
["headers"]=>
array(7) {
[0]=>
string(11) "abc_123_ghi"
[1]=>
string(8) "dangdarn"
[2]=>
string(6) "oops32"
[3]=>
**string(8) "poss_dup"**
[4]=>
string(10) "poss_dup_1"
[5]=>
string(9) "pos_s_dup"
[6]=>
**&string(8) "poss_dup"**
}
["header_test"]=>
array(6) {
["abc_123_ghi"]=>
int(1)
["dangdarn"]=>
int(1)
["oops32"]=>
int(1)
["poss_dup"]=>
int(2)
["pos_s_dup"]=>
int(1)
["bad_chars_3_9"]=>
int(1)
}
And now here is what works, which is to use $original_array[$key] = $new_value format:
$header_test = array();
foreach($headers as $key => $header) {
$temp = $header;
if(array_key_exists($temp,$header_test)) {
**$headers[$key] = $header . '_' . $header_test[$header];**
$header_test[$temp]++;
unset($temp);
} else {
$header_test[$temp] = 1;
}
}
var_dump:
["headers"]=>
array(7) {
[0]=>
string(11) "abc_123_ghi"
[1]=>
string(8) "dangdarn"
[2]=>
string(6) "oops32"
**[3]=>
string(8) "poss_dup"
[4]=>
string(10) "poss_dup_1"**
[5]=>
string(9) "pos_s_dup"
**[6]=>
string(13) "bad_chars_3_9"**
}
["header_test"]=>
array(6) {
["abc_123_ghi"]=>
int(1)
["dangdarn"]=>
int(1)
["oops32"]=>
int(1)
["poss_dup"]=>
int(2)
["pos_s_dup"]=>
int(1)
["bad_chars_3_9"]=>
int(1)
}
VolkerK came up with the solution. Besides his other good suggestions, the key thing was unsetting $header after the foreach loop.
just taking your code
produces
on my machine using php 5.3.5/win32. Looks like your “real” code does something else to $header in and/or after the loop.
A bit simplified (eliminating $tmp):
prints