I have an array $data
fruit => apple,
seat => sofa,
etc. I want to loop through so that each key becomes type_key[0]['value'] so eg
type_fruit[0]['value'] => apple,
type_seat[0]['value'] => sofa,
and what I thought would do this, namely
foreach ($data as $key => $value)
{
# Create a new, renamed, key.
$array[str_replace("/(.+)/", "type_$1[0]['value']", $key)] = $value;
# Destroy the old key/value pair
unset($array[$key]);
}
print_r($array);
Doesn't work. How can I make it work?
Also, I want everything to be in the keys (not the values) to be lowercase: is there an easy way of doing this too? Thanks.
Do you mean you want to make the keys into separate arrays? Or did you mean to just change the keys in the same array?
$array = array();
foreach ($data as $key => $value)
{
$array['type_' . strtolower($key)] = array(array('value' => $value));
}
if you want your keys to be separate variables, then do this:
extract($array);
Now you will have $type_fruit and $type_sofa. You can find your values as $type_fruit[0]['value'], since we put an extra nested array in there.
Your requirements sound... suspect. Perhaps you meant something like the following:
$arr = array('fruit' => 'apple', 'seat' => 'sofa');
$newarr = array();
foreach ($arr as $key => $value)
{
$newkey = strtolower("type_$key");
$newarr[$newkey] = array(array('value' => $value));
}
var_dump($newarr);
First I wouldn't alter the input-array but create a new one unless you're in serious, serious trouble with your memory limit.
And then you can't simply replace the key to add a deeper nested level to an array.
$x[ 'abc[def]' ] is still only referencing a top-level element, since abc[def] is parsed as one string, but you want $x['abc']['def'].
$data = array(
'fruit' => 'apple',
'seat' => 'sofa'
);
$result = array();
foreach($data as $key=>$value) {
$target = 'type_'.$key;
// this might be superfluous, but who knows... if you want to process more than one array this might be an issue.
if ( !isset($result[$target]) || !is_array($result[$target]) ) {
$result[$target] = array();
}
$result[$target][] = array('value'=>$value);
}
var_dump($result);
for starters
$array[str_replace("/(.+)/", "type_$1[0]['value']", $key)] = $value;
should be
$array[str_replace("/(.+)/", type_$1[0]['value'], $key)] = $value;
Related
Let say I have an array as follows:
$my_array = array(
"fruit1" => "apple",
"fruit2" => "orange",
"notfruit" => "hamburger",
"fruit3" => "banana"
)
Is there a way I can choose to start with $my_array['notfruit'] in an foreach loop of PHP? I don't care the sequence except the first one.
Currently I can think of copying the whole piece of code once and change it specifically for $my_array['notfruit'], then unset it from the array to use foreach loop to go through the remaining. i.e.
echo $my_array['notfruit']."is not fruit. Who put that in the array?";
unset ($my_array['notfruit']);
foreach ($my_array as $values) {
echo $values." is fruit. I love fruit so I like ".$values;
}
It works but it sounds stupid, and can cause problem if the content in the foreach loop is long.
You can filter out any element with a key that doesn't begin with fruit pretty easily
$fruits = array_filter(
$my_array,
function ($key) {
return fnmatch('fruit*', $key);
},
ARRAY_FILTER_USE_KEY
);
var_dump($fruits);
though using array_filter() with the keys like this does require PHP >= 5.6
EDIT
For earlier versions of PHP, you can swap the keys/values before filtering; then flip them again afterwards
$fruits = array_flip(
array_filter(
array_flip($my_array),
function ($value) {
return fnmatch('fruit*', $value);
}
)
);
var_dump($fruits);
Short answer, no.
You can, however pull whatever functionality you intended to have in the foreach into a funcion, then call the funcion specifically for the notfruit value, then run the foreach.
function foo($val) {
// do stuff with $val
}
$my_array = array(
"fruit1" => "apple",
"fruit2" => "orange",
"notfruit" => "hamburger",
"fruit3" => "banana"
)
foo($my_array['nofriut']);
unset($my_array['nofruit']);
foreach($my_array as $val) {
foo($val);
}
EDIT
Or if your case is as simple as your updated question, simply check if the key is nofruit
foreach($my_array as $key => $val) {
if($key === "nofruit") {
echo "$val is not fruit. Who put that in the array?";
} else {
echo "$val is fruit. I love fruit so I like $val";
}
}
You can use addition in arrays, which is more performant than array_unshift.
So unset it, and then add it back:
unset($my_array['notfruit']);
$my_array = array('notfruit' => 'hamburger') + $my_array;
var_dump($my_array);
Or if you want to use a variable:
$keyToMove = 'notfruit';
$val = $my_array[$keyToMove];
unset($my_array[$keyToMove]);
$newArray = array($keyToMove => $val) + $my_array;
var_dump($newArray);
Obviously you can put this all in a loop, applying it to any that you need to move.
Try this..
<?php
$my_array = array(
"fruit1" => "apple",
"fruit2" => "orange",
"notfruit" => "hamburger",
"fruit3" => "banana"
);
$new_value['notfruit'] = $my_array['notfruit'];
unset($my_array['notfruit']);
$newarray=array_merge($new_value,$my_array);
print_r($newarray);
?>
Result:Array ( [notfruit] => hamburger [fruit1] => apple [fruit2] => orange [fruit3] => banana )
There is too many options.
1 . Using array_merge or array_replace (i think that it is the simplest way)
$my_array = array_merge(['notfruit' => null], $my_array);
// $my_array = array_replace(['notfruit' => null], $my_array);
foreach ($my_array as $key => $value) {
var_dump($key, $value);
}
2 . Using generators.
$my_array = array(
"fruit1" => "apple",
"fruit2" => "orange",
"notfruit" => "hamburger",
"fruit3" => "banana"
);
$generator = function($my_array){
yield 'notfruit'=>$my_array['notfruit'];
unset($my_array['notfruit']);
foreach($my_array as $key => $value)
yield $key => $value;
};
foreach ($generator($my_array) as $key=>$value){
var_dump($key, $value);
}
3 . Readding value
$no_fruit = $my_array['nofruit'];
unset($my_array['nofruit']);
$my_array['nofruit'] = $no_fruit;
$my_array = array_reverse($my_array, true);
foreach ($my_array as $key=>$value){
var_dump($key, $value);
}
4 . Using infinitive iterator
$infinate = new InfiniteIterator(new ArrayIterator($my_array));
$limit_iterator = new LimitIterator(
$infinate,
array_search('notfruit', array_keys($my_array)), // position of desired key
count($my_array));
foreach ($limit_iterator as $key => $value) {
var_dump($key, $value);
}
$no_fruit = $my_array['nofruit']; // grab the value
unset($my_array['nofruit']); // remove value from array
array_unshift($my_array, $no_fruit); // add value at the beginning
or
$no_fruit = $my_array['nofruit']; // grab the value
unset($my_array['nofruit']); // remove value from array
$my_array = array('nofruit' => $no_fruit ) + $my_array; // add value at the beginning
You can "change" the key of an array element simply by setting the new key and removing the old:
$array[$newKey] = $array[$oldKey];
unset($array[$oldKey]);
But this will move the key to the end of the array.
Is there some elegant way to change the key without changing the order?
(PS: This question is just out of conceptual interest, not because I need it anywhere.)
Tested and works :)
function replace_key($array, $old_key, $new_key) {
$keys = array_keys($array);
if (false === $index = array_search($old_key, $keys, true)) {
throw new Exception(sprintf('Key "%s" does not exist', $old_key));
}
$keys[$index] = $new_key;
return array_combine($keys, array_values($array));
}
$array = [ 'a' => '1', 'b' => '2', 'c' => '3' ];
$new_array = replace_key($array, 'b', 'e');
Something like this may also work:
$langs = array("EN" => "English",
"ZH" => "Chinese",
"DA" => "Danish",
"NL" => "Dutch",
"FI" => "Finnish",
"FR" => "French",
"DE" => "German");
$json = str_replace('"EN":', '"en":', json_encode($langs));
print_r(json_decode($json, true));
OUTPUT:
Array
(
[en] => English
[ZH] => Chinese
[DA] => Danish
[NL] => Dutch
[FI] => Finnish
[FR] => French
[DE] => German
)
One way would be to simply use a foreach iterating over the array and copying it to a new array, changing the key conditionally while iterating, e.g. if $key === 'foo' then dont use foo but bar:
function array_key_rename($array, $oldKey, $newKey)
{
$newArray = [];
foreach ($array as $key => $value) {
$newArray[$key === $oldKey ? $newKey : $key] = $value;
}
return $newArray;
}
Another way would be to serialize the array, str_replace the serialized key and then unserialize back into an array again. That isnt particular elegant though and likely error prone, especially when you dont only have scalars or multidimensional arrays.
A third way - my favorite - would be you writing array_key_rename in C and proposing it for the PHP core ;)
Check keys existence before proceeding…
Otherwise the result can be catastrophic if the new key already exists... or unnecessary processing time/memory consumption if the key to be replaced does not exist.
function array_rename_key( array $array, $old_key, $new_key ) {
// if $new_key already exists, or if $old_key doesn't exists
if ( array_key_exists( $new_key, $array ) || ! array_key_exists( $old_key, $array ) ) {
return $array;
}
$new_array = [];
foreach ( $array as $k => $v ) {
$new_array[ $k === $old_key ? $new_key : $k ] = $v;
}
return $new_array;
}
Do a double flip! At least that is all I can think of:
$array=("foo"=>"bar","asdf"=>"fdsa");
$array=array_flip($array);
$array["bar"]=>'newkey';
$array=array_flip($array);
We are using this function for changing multiple array keys within an array keeping the order:
function replace_keys($array, $keys_map) {
$keys = array_keys($array);
foreach($keys_map as $old_key=>$new_key){
if (false === $index = array_search($old_key, $keys)) {
continue;
}
$keys[$index] = $new_key;
}
return array_combine($keys, array_values($array));
}
You can pass an array as $keys_map, like this:
$keys_map=array("old_key_1"=>"new_key_1", "old_key_2"=>"new_key_2",...)
This solution is based on Kristian one.
If possible, one can also put the key to change at the end of the array in the moment of creation :
$array=array('key1'=>'value1','key2'=>'value2','keytochange'=>'value');
$x=$array['keytochange'];
unset($array['keytochange']);
$array['newkey']=$x;
You could use array_combine. It merges an array for keys and another for values...
For instance:
$original_array =('foo'=>'bar','asdf'=>'fdsa');
$new_keys = array('abc', 'def');
$new_array = array_combine($new_keys, $original_array);
Consider the following array:
$array[23] = array(
[0] => 'FOO'
[1] => 'BAR'
[2] => 'BAZ'
);
Whenever I want to work with the inner array, I do something like this:
foreach ($array as $key => $values) {
foreach ($values as $value) {
echo $value;
}
}
The outer foreach-loop is there to split the $key and $value-pairs of $array. This works fine for arrays with many keys ([23], [24], ...)but seems redundant if you know beforehand that $array only has one key (23 in this case). In a case as such, isn't there a better way to split the key from the values? Something like
split($array into $key => $values)
foreach ($values as $value) {
echo $value;
}
I hope I made myself clear.
reset returns the first element of you array and key returns its key:
$your_inner_arr = reset($array);
$your_key = key($array);
Yea, just get rid of your first foreach and define the array you're using with the known $key of your outter array.
foreach ($array[23] as $key =>$val):
//do whatever you want in here
endforeach;
If an array has only one element, you can get it with reset:
$ar = array(23 => array('foo', 'bar'));
$firstElement = reset($ar);
A very succinct approach would be
foreach(array_shift($array) as $item) {
echo $item;
}
You can "change" the key of an array element simply by setting the new key and removing the old:
$array[$newKey] = $array[$oldKey];
unset($array[$oldKey]);
But this will move the key to the end of the array.
Is there some elegant way to change the key without changing the order?
(PS: This question is just out of conceptual interest, not because I need it anywhere.)
Tested and works :)
function replace_key($array, $old_key, $new_key) {
$keys = array_keys($array);
if (false === $index = array_search($old_key, $keys, true)) {
throw new Exception(sprintf('Key "%s" does not exist', $old_key));
}
$keys[$index] = $new_key;
return array_combine($keys, array_values($array));
}
$array = [ 'a' => '1', 'b' => '2', 'c' => '3' ];
$new_array = replace_key($array, 'b', 'e');
Something like this may also work:
$langs = array("EN" => "English",
"ZH" => "Chinese",
"DA" => "Danish",
"NL" => "Dutch",
"FI" => "Finnish",
"FR" => "French",
"DE" => "German");
$json = str_replace('"EN":', '"en":', json_encode($langs));
print_r(json_decode($json, true));
OUTPUT:
Array
(
[en] => English
[ZH] => Chinese
[DA] => Danish
[NL] => Dutch
[FI] => Finnish
[FR] => French
[DE] => German
)
One way would be to simply use a foreach iterating over the array and copying it to a new array, changing the key conditionally while iterating, e.g. if $key === 'foo' then dont use foo but bar:
function array_key_rename($array, $oldKey, $newKey)
{
$newArray = [];
foreach ($array as $key => $value) {
$newArray[$key === $oldKey ? $newKey : $key] = $value;
}
return $newArray;
}
Another way would be to serialize the array, str_replace the serialized key and then unserialize back into an array again. That isnt particular elegant though and likely error prone, especially when you dont only have scalars or multidimensional arrays.
A third way - my favorite - would be you writing array_key_rename in C and proposing it for the PHP core ;)
Check keys existence before proceeding…
Otherwise the result can be catastrophic if the new key already exists... or unnecessary processing time/memory consumption if the key to be replaced does not exist.
function array_rename_key( array $array, $old_key, $new_key ) {
// if $new_key already exists, or if $old_key doesn't exists
if ( array_key_exists( $new_key, $array ) || ! array_key_exists( $old_key, $array ) ) {
return $array;
}
$new_array = [];
foreach ( $array as $k => $v ) {
$new_array[ $k === $old_key ? $new_key : $k ] = $v;
}
return $new_array;
}
Do a double flip! At least that is all I can think of:
$array=("foo"=>"bar","asdf"=>"fdsa");
$array=array_flip($array);
$array["bar"]=>'newkey';
$array=array_flip($array);
We are using this function for changing multiple array keys within an array keeping the order:
function replace_keys($array, $keys_map) {
$keys = array_keys($array);
foreach($keys_map as $old_key=>$new_key){
if (false === $index = array_search($old_key, $keys)) {
continue;
}
$keys[$index] = $new_key;
}
return array_combine($keys, array_values($array));
}
You can pass an array as $keys_map, like this:
$keys_map=array("old_key_1"=>"new_key_1", "old_key_2"=>"new_key_2",...)
This solution is based on Kristian one.
If possible, one can also put the key to change at the end of the array in the moment of creation :
$array=array('key1'=>'value1','key2'=>'value2','keytochange'=>'value');
$x=$array['keytochange'];
unset($array['keytochange']);
$array['newkey']=$x;
You could use array_combine. It merges an array for keys and another for values...
For instance:
$original_array =('foo'=>'bar','asdf'=>'fdsa');
$new_keys = array('abc', 'def');
$new_array = array_combine($new_keys, $original_array);
I am trying to unset a group of array keys that have the same prefix. I can't seem to get this to work.
foreach ($array as $key => $value) {
unset($array['prefix_' . $key]);
}
How can I get unset to see ['prefix_' . $key] as the actual variable? Thanks
UPDATE: The $array keys will have two keys with the same name. Just one will have the prefix and there are about 5 keys with prefixed keys:
Array {
[name] => name
[prefix_name] => other name
}
I don't want to remove [name] just [prefix_name] from the array.
This works:
$array = array(
'aa' => 'other value aa',
'prefix_aa' => 'value aa',
'bb' => 'other value bb',
'prefix_bb' => 'value bb'
);
$prefix = 'prefix_';
foreach ($array as $key => $value) {
if (substr($key, 0, strlen($prefix)) == $prefix) {
unset($array[$key]);
}
}
If you copy/paste this code at a site like http://writecodeonline.com/php/, you can see for yourself that it works.
You can't use a foreach because it's only a copy of the collection. You'd need to use a for or grab the keys separately and separate your processing from the array you want to manipulate. Something like:
foreach (array_keys($array) as $keyName){
if (strncmp($keyName,'prefix_',7) === 0){
unset($array[$keyName]);
}
}
You're also already iterating over the collection getting every key. Unless you had:
$array = array(
'foo' => 1,
'prefix_foo' => 1
);
(Where every key also has a matching key with "prefix_" in front of it) you'll run in to trouble.
I'm not sure I understand your question, but if you are trying to unset all the keys with a specific prefix, you can iterate through the array and just unset the ones that match the prefix.
Something like:
<?php
foreach ($array as $key => $value) { // loop through keys
if (preg_match('/^prefix_/', $key)) { // if the key stars with 'prefix_'
unset($array[$key]); // unset it
}
}
You're looping over the array keys already, so if you've got
$array = (
'prefix_a' => 'b',
'prefix_c' => 'd'
etc...
)
Then $keys will be prefix_a, prefix_c, etc... What you're doing is generating an entirely NEW key, which'd be prefix_prefix_a, prefix_prefix_c, etc...
Unless you're doing something more complicated, you could just replace the whole loop with
$array = array();
I believe this should work:
foreach ($array as $key => $value) {
unset($array['prefix_' . str_replace('prefix_', '', $key]);
}