Change $key of associative array in a foreach loop in php - php

I have an array like this:
array(
'firstName' => 'Joe',
'lastName' => 'Smith'
)
I need to loop over every element in my array and in the end, the array should look like this:
array(
'FirstName' => 'Joe',
'LastName' => 'Smith'
)
Failed idea was:
foreach($array as $key => $value)
{
$key = ucfirst($key);
}
This obviously will not work, because the array is not passed by reference. However, all these attempts also fail:
foreach(&$array as $key => $value)
{
$key = ucfirst($key);
}
foreach($array as &$key => $value)
{
$key = ucfirst($key);
}
Pretty much at my wits end with this one. I'm using Magento 1.9.0.1 CE, but that's pretty irrelevant for this problem. If you must know, the reason I have to do this is because I have a bunch of object that's I'm returning as an array to be assembled into a SOAP client. The API I'm using requires the keys to begin with a capital letter...however, I don't wish to capitalize the first letter of my object's variable names. Silly, I know, but we all answer to someone, and that someone wants it that way.

unset it first in case it is already in the proper format, otherwise you will remove what you just defined:
foreach($array as $key => $value)
{
unset($array[$key]);
$array[ucfirst($key)] = $value;
}

You can't modify the keys in a foreach, so you would need to unset the old one and create a new one. Here is another way:
$array = array_combine(array_map('ucfirst', array_keys($array)), $array);
Get the keys using array_keys
Apply ucfirst to the keys using array_map
Combine the new keys with the values using array_combine

The answers here are dangerous, in the event that the key isn't changed, the element is actually deleted from the array. Also, you could unknowingly overwrite an element that was already there.
You'll want to do some checks first:
foreach($array as $key => $value)
{
$newKey = ucfirst($key);
// does this key already exist in the array?
if(isset($array[$newKey])){
// yes, skip this to avoid overwritting an array element!
continue;
}
// Is the new key different from the old key?
if($key === $newKey){
// no, skip this since the key was already what we wanted.
continue;
}
$array[$newKey] = $value;
unset($array[$key]);
}
Of course, you'll probably want to combine these "if" statements with an "or" if you don't need to handle these situations differently.

This might work:
foreach($array as $key => $value) {
$newkey = ucfirst($key);
$array[$newkey] = $value;
unset($array[$key]);
}
but it is very risky to modify an array like this while you're looping on it. You might be better off to store the unsettable keys in another array, then have a separate loop to remove them from the original array.
And of course, this doesn't check for possible collisions in the aray, e.g. firstname -> FirstName, where FirstName already existed elsewhere in the array.
But in the end, it boils down to the fact that you can't "rename" a key. You can create a new one and delete the original, but you can't in-place modify the key, because the key IS the key to lookup an entry in the aray. changing the key's value necessarily changes what that key is pointing at.

Top of my head...
foreach($array as $key => $value){
$newKey = ucfirst($key);
$array[$newKey] = $value;
unset($array[$key]);
}
Slightly change your way of thinking. Instead of modifying an existing element, create a new one, and remove the old one.

If you use laravel or have Illuminate\Support somewhere in your dependencies, here's a chainable way:
>>> collect($array)
->keys()
->map(function ($key) {
return ucfirst($key);
})
->combine($array);
=> Illuminate\Support\Collection {#1389
all: [
"FirstName" => "Joe",
"LastName" => "Smith",
],
}

Related

Multidimensional array keys to variable

sadly i havent found any solution yet.
I have an multidimensional array which looks like this:
Array
(
[0] => Array
(
[Symbol] => CASY.US
[Position] => 169873920
)
[1] => Array
(
[Symbol] => US500
[Position] => 168037428
) )
Now i want to write the name of the keys of the inner array into variables so that i have these variables with the values:
$col1 = "Symbol"
$col2 = "Position"
How can i achieve that? Somehow with a couple of foreach loops?
Background: After that i want to check if the columns have the right name for a validation.
Thanks in advance!
Loop nested and save the keys to an array with "col" and an integer that you later can (if you really must extract), but I recommend to keep them in the array.
foreach($array as $subarray){
$i = 1;
foreach($subarray as $key => $val){
$keys["col" . $i] = $key;
$i++;
}
break; // no need to keep looping if the array is uniform
}
//if you must:
extract($keys);
https://3v4l.org/ALVtp
If the subarrays are not the same then you need to loop all subarrays and see if the key has already been saved, if not save it else skip it.
$keys =[];
$i = 1;
foreach($array as $subarray){
foreach($subarray as $key => $val){
if(!in_array($key, $keys)){
$keys["col" . $i] = $key;
$i++;
}
}
}
var_dump($keys);
//if you must:
extract($keys);
var_dump($col1, $col2, $col3);
https://3v4l.org/EklPK
Honestly I would do something like this:
$required = array_flip(['Symbol', 'Position']); //flip because I am lazy like that ['Symbol'=>0, 'Position'=>1]
foreach($array as $subarray){
$diff = array_diff_key($required, $subarray);
//prints any keys in $required that are not in $subarray
print_r($diff);
if(!empty($diff)){
//some required keys were missed
}
}
While its not clear how you validate these the reason is as I explained in this comment
it still doesn't solve the problem, as you really have no way to know what the keys will be (if they are not uniform). So with my example foo is $col3 what if I have bar later that's $col4 what if the order is different next time.... they will be different numbers. Sure it's a few what if's but you have no guarantees here.
By dynamically numbering the keys, if the structure of the array ever changes you would have no idea what those dynamic variables contain, and as such no idea how to validate them.
So even if you manage to make this work, if your data ever changes you going to have to re-visit the code.
In any case if your wanting to see if each array contains the keys it needs to, what I put above would be a more sane way to do it.

How to remove a specific empty array from $_SESSION with PHP?

I have set of arrays with combination of set/unset session value from the previous page. I want to remove the unset value. But I don't know how to remove it because it's have no key to tell which one.
$array
Array (
[4ltr] => 5
[] =>
[800ml] => 10
)
As you see the 2nd array is empty both key and value. I can thinking of the empty() but again, how to tell the script to remove the key with blank value?
Okey, I fxxk up. This is easy like shssst.
foreach ($_SESSION['ss'] as $key => $value) {
if (empty($value)) {
unset($_SESSION['ss'][$key]);
}
}
Another approach would be without assigning the modified data to a variable. It's just a fancy pattern. If you are doing that on every page then you can just write a global function to check.
array_walk($data, function($item, $key) use (&$data){
if(empty($item)){
unset($data[$key]);
}
});
print_r($data)
You can do it with,
$_SESSION= array_filter($_SESSION, function($v, $k){ return $v && $k;}, ARRAY_FILTER_USE_BOTH)
You can test below code, demo
print_r(array_filter(array('' => '2', '3' =>3), function($v, $k){ return $v && $k;}, ARRAY_FILTER_USE_BOTH));

PHP array, substitute the key within a foreach loop

I have read a lot of posts and have not been able to find a solution to my issue.
I have a $_POST array named "Water", $_POST['Water'] and its contents are:
[Water] => Array ( [0] => 55.0 [1] => 22 )
Is it possible to use the name of the post inside a foreach loop so the $key could use the name "Water":
foreach($_POST['Water'] as $key => $val) {
$fields[] = "$field = '$val'";
//echo "Key: $key, Value: $val<br/>\n";
}
Many thanks for your time.
Not really. foreach() operates on the contents of an array. Whatever actually contains that array is outside of foreach's view. If you want to dynamically use the Water key elsewhere, you'll have to do that yourself:
$key = 'Water'
foreach($_POST[$key] as $val) {
$fields[] = "$key = '$val'";
}
If I read this right you basically want $field='water' inside the foreach. This can be done be rethinking the way we build the foreach.
You simply need to make the field value a variable and pass use that rather everywhere the value is needed.
$field = 'Water';
foreach($_POST[$field] as $key => $val) {
$fields[] = "$field = '$val'";
//echo "Key: $key, Value: $val<br/>\n";
}
The advantage of this approach is that if you change your mind and the $_POST key is later called, "liquid" one single line needs to be edited and that is all. Furthermore, if your foreach were part of a function $field could be a function parameter. In a roundabout way, you are actually getting pretty close to some code reuse principles.

PHP push values into associative array

I can't find an answer to this anywhere.
foreach ($multiarr as $array) {
foreach ($array as $key=>$val) {
$newarray[$key] = $val;
}
}
say $key has duplicate names, so when I am trying to push into $newarray it actually looks like this:
$newarray['Fruit'] = 'Apples';
$newarray['Fruit'] = 'Bananas';
$newarray['Fruit'] = 'Oranges';
The problem is, the above example just replaces the old value, instead of pushing into it.
Is it possible to push values like this?
Yes, notice the new pair of square brackets:
foreach ($multiarr as $array) {
foreach ($array as $key=>$val) {
$newarray[$key][] = $val;
}
}
You may also use array_push(), introducing a bit of overhead, but I'd stick with the shorthand most of the time.
I'll offer an alternative to moonwave99's answer and explain how it is subtly different.
The following technique unpacks the indexed array of associative arrays and serves each subarray as a separate parameter to array_merge_recursive() which performs the merging "magic".
Code: (Demo)
$multiarr = [
['Fruit' => 'Apples'],
['Fruit' => 'Bananas'],
['Fruit' => 'Oranges'],
['Veg' => 'Carrot'],
//['Veg' => 'Leek'],
];
var_export(
array_merge_recursive(...$multiarr)
);
As you recursively merge, if there is only one value for a respective key, then a subarray is not used, if there are multiple values for a key, then a subarray is used.
See this action by uncommenting the Leek element.
p.s. If you know that you are only targetting a single column of data and you know the key that you are targetting, then array_column() would be a wise choice.
Code: (Demo)
var_export(
['Fruit' => array_column($multiarr, 'Fruit')]
);

Using foreach effectively in PHP

So I don't think I'm making full use of the foreach loop. Here is how I understand foreach.
It goes like foreach(arrayyouwanttoloopthrough as onevalueofthatarray)
No counter or incrementing required, it automatically pulls an array, value by value each loop, and for that loop it calls the value whatever is after the "as".
Stops once it's done with the array.
Should basically replace "for", as long as dealing with an array.
So something I try to do a lot with foreach is modify the array values in the looping array. But in the end I keep finding I have to use a for loop for that type of thing.
So lets say that I have an array (thing1, thing2, thing3, thing4) and I wanted to change it....lets say to all "BLAH", with a number at the end, I'd do
$counter = 0;
foreach($array as $changeval){
$counter++;
$changeval = "BLAH".$counter;
}
I would think that would change it because $changeval should be whatever value it's at for the array, right? But it doesn't. The only way I could find to do that in a] foreach is to set a counter (like above), and use the array with the index of counter. But to do that I'd have to set the counter outside the loop, and it's not even always reliable. For that I'd think it would be better to use a for loop instead of foreach.
So why would you use foreach over for? I think I'm missing something here because foreach has GOT to be able to change values...
Thanks
OH HEY One more thing. Are variables set in loops (like i, or key) accessible outside the loop? If I have 2 foreach loops like
foreach(thing as value)
would I have to make the second one
foreach(thing2 as value2) ]
or else it would have some problems?
You can use a reference variable instead:
foreach ($array as &$value)
{
$value = "foo";
}
Now the array is full of foo (note the & before $value).
Normally, the loop variable simply contains a copy of the corresponding array element, but the & (ampersand) tells PHP to make it a reference to the actual array element, rather than just a copy; hence you can modify it.
However, as #Tadeck says below, you should be careful in this case to destroy the reference after the loop has finished, since $value will still point to the final element in the array (so it's possible to accidentally modify it). Do this with unset:
unset($value);
The other option would be to use the $key => $value syntax:
foreach ($array as $key => $value)
{
$array[$key] = "foo";
}
To answer your second question: yes, they are subsequently accessible outside the loop, which is why it's good practice to use unset when using reference loop variables as in my first example. However, there's no need to use new variable names in subsequent loops, since the old ones will just be overwritten (with no unwanted consequences).
You want to pass by reference:
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value)
{
$value = $value * 2;
}
// $arr is now array(2, 4, 6, 8)
The extended foreach syntax is like this:
foreach ($array as $key => $value) {
}
Using the $key, you can index the original array:
foreach ($array as $key => $value) {
$array[$key] = "BLAH";
}
Incrementing from 0 to ...
foreach($array as $changeval){
if (!isset($counter)) { $counter = 0; }
$counter++;
$changeval = "BLAH".$counter;
}
Using the index/key of the ARRAY
foreach($array as $key => $changeval){
$changeval = "BLAH".$key;
}
You can use the key when looping with foreach:
foreach ($array as $key => $value)
{
$array[$key] = "foo";
}
But note that using a reference like Will suggested will be faster for such a case - but anyway, the $key => $value-syntax is quite useful sometimes.

Categories