confusing multidimensional array in php with foreach getting error - php

what is use of multidimensional array(2D,3D or what is the limit in multidimensional array) and foreach()?
foreach() is use for printing values inside array?
In case of multidimensional array why nested loop is important?
Errors:
Notice: Array to string conversion in C:\xampp\htdocs\example\basic\foreach2.php on line 9
Arrayarray(3) { [0]=> int(4) [1]=> int(5) [2]=> int(7) }
Notice: Array to string conversion in C:\xampp\htdocs\example\basic\foreach2.php on line 11
$items = array(1,2,3,
array(4,5,7
),
8,54,4,5,5);
foreach($items as $key => $value)
{
echo $value;
var_dump($value);
echo $key ."pair match".$value . "<br>";
}
HOW do I access this array?
$a_services = array(
'user-login' => array(
'operations' => array(
'retrieve' => array(
'help' => 'Retrieves a user',
'callback' => 'android',
'file' => array('type' => 'inc', 'module' => 'android_services'),
'access callback' => 'services',
'args' => array(
array(
'name' => 'phone_no',
'type' => 'string',
'description' => 'The uid ',
'source' => array('path' => 0),
'optional' => FALSE,
),
),
),
),
),
);
print_r($a_services['$android_services ']['user-login']['operations']['retrieve']['callback']);
print_r($a_services['$android_services ']['user-login']['operations']['retrieve']['callback']['args']['name']);
Error 1. Notice: Array to string conversion
2. Undefined index: $android_services
3. How to print with help of foreach
4. above array is 4 dimensional??????

To loop through this kind of array you need some sort of recursiveness.
I usually call a function inside the for each. the function tests whether the current element is an array. If so the functions call itself. If not the function does whatever (echo the value in your example).
Something like:
foreach($a_services as $key => $value) {
do_your_thing($value);
}
function do_your_thing($recvalue)
{
if (is_array($recvalue))
{
foreach($recvalue as $key => $value)
{
do_your_thing($value);
}
}
else
{
echo $recvalue;
}
return $recvalue;
}

You can define multidimension arrays (arrays including oher arrays) in PHP.
For example you have 2 different lists, one for grocery shopping, one for daily task.
$lists = array(
'grocery' => array('banana', 'apple'),
'tasks' => array('go to work', 'wash dishes'),
);
If you want to check all levels of arrays, you should use nested loops. For example you can use foreach, it will iterate over arrays first level.
foreach($lists as $list)
return $list; // returns grocery[] and tasks[]
As you see this loop returning other loop. So if you need to list all grocery[] array items, you need iterate again in this array.
foreach($lists as $list)
foreach($list as $k => $l)
if($k == 'grocery')
echo $l; // echos "banana","apple"
Nested loops are important (and necessary) to reach multidimensional arrays contents especially if you don't know structure of the array. These loops will find all array items for you. But if you know structure, you can directly use $lists['grocery'] to reach grocery array or $lists['grocery'][0] to reach first element of your grocery list.

Related

PHP Merge two arrays in to each other, using an index array as a reference - Two arrays as output

I am trying to take two arrays, and merge them to each other. The first array serves as an 'index' array, that is - that is the format that the output arrays desirably would be:
$array1 = [
'DIV1' => 'Some element data',
'SUPPLEMENTAL' => [
'RPC' => '10.24.122.32',
'PORT' => '8080'
],
'ASG' => 'some arbitrary data'
];
$array2 = [
'DIV2' => 'Some more element data',
'ASG' => 'different arbitrary data',
'DIV1' => 'Some element data that refers to the other object'
'SUPPLEMENTAL' => [
'RPC' => '10.24.123.1'
]
];
So after the merge, we would effectively have two arrays. This can be done as a a single function called twice, which passes each array as parameters (reversed for the second call - and somehow defining the index array). The keys would be carried over -only-, no values. We would end up with arrays looking like this:
$array1 = [
'DIV1' => 'Some element data',
'DIV2' => '', // blank because only key was moved
'SUPPLEMENTAL' => [
'RPC' => '10.24.122.32',
'PORT' => '8080'
],
'ASG' => 'some arbitrary data'
];
$array2 = [
'DIV1' => 'Some element data that refers to the other object'
'DIV2' => 'Some more element data',
'SUPPLEMENTAL' => [
'RPC' => '10.24.123.1',
'PORT' => '' // blank because only key was moved
],
'ASG' => 'different arbitrary data'
];
It is not -extremely- important that the imported (blank) keys are put in some order, but the preservation of order of existing elements is important. As long as it abides by the index arrays order definition (array1 in this case).
I think I would need to do some sort of nested sort for the multiple dimensions.
Because your data doesn't have keys in the same order it'll be difficult to maintain key order, but you can achieve what you need with a recursive function:
function recursiveReKeyArrays(array $array1, array $array2)
{
// Loop through the array for recursion
foreach ($array2 as $key => $value) {
if (!is_array($value)) {
continue;
}
$array1[$key] = recursiveReKeyArrays($array1[$key], $value);
}
// Find the differences in the keys
foreach (array_diff_key($array2, $array1) as $key => $value) {
$array1[$key] = null;
}
return $array1;
}
This will loop through the second array, find any values which are arrays and recurse into them and find any missing keys and set them to null.
This will give you this output:
Array
(
[DIV1] => Some element data
[SUPPLEMENTAL] => Array
(
[RPC] => 10.24.122.32
[PORT] => 8080
)
[ASG] => some arbitrary data
[DIV2] =>
)
Array
(
[DIV2] => Some more element data
[ASG] => different arbitrary data
[DIV1] => Some element data that refers to the other object
[SUPPLEMENTAL] => Array
(
[RPC] => 10.24.123.1
[PORT] =>
)
)
Example here: http://ideone.com/5ml1y4

Copying a multidimensional array

I get() an multidimensional array and store it inside the $products variable.
I need to Make a copy of that array to create it into a new Webshop because the export provided by the API does not work so I have created this script to copy the data:
foreach ($products as $id => $product) {
$copy = $products[$id];
$createdProducts = $apiSkylux->products->create(
array(
'id' => $copy['id'],
'createdAt' => $copy['createdAt'],
'updatedAt' => $copy['updatedAt'],
'isVisible' => $copy['isVisible'],
'visibility' => $copy['visibility'],
'data01' => $copy['data01'],
'data02' => $copy['data02'],
'data03' => $copy['data03'],
'url' => $copy['url'],
'title' => $copy['title'],
'fulltitle' => $copy['fulltitle'],
'description' => $copy['description'],
'content' => $copy['content'],
'set' => $copy['set'],
'brand' => $copy['brand'],
'categories' => $copy['categories'],
'deliverydate' => $copy['deliverydate'],
'image' => $copy['image'],
'images' => $copy['images'],
'relations' => $copy['relations'],
'reviews' => $copy['reviews'],
'type' => $copy['type'],
'attributes' => $copy['attributes'],
'supplier' => $copy['supplier'],
'tags' => $copy['tags'],
'variants' => $copy['variants'],
'movements' => $copy['movements'],
)
);
}
The copy is working. But i thought #2016 and all, can't this be achieved with less lines of code?
This is what I receive with var_dump of the first array:
var_dump($products[0]);
exit;
//result
array(28) {
["id"]=>
int(26136946)
//rest of array
So I can see the array has a number (28) , what does this represent?
I've tried several attempts, closest attempt was :
$copy = $products[$id];
$createProducts = $products;
$createdProducts = $apiSkylux->products->create($createProducts);
But then I also got an error : Invalid data input
Can I copy the data from the array easier then the method I am currently using?
array(
'id' => $copy['id'],
...
)
This can be reduced to simply:
$copy
Yes, reassigning every single key into a new array is the same as using the original array in the first place.
foreach($products as $id => $product){
$copy = $products[$id];
This can be reduced to:
foreach ($products as $product){
$copy = $product;
Obviously you could leave out $copy entirely and just use $product.
Bottom line:
foreach ($products as $product) {
$createdProducts = $apiSkylux->products->create($product);
}
What you do with $createdProducts I don't know; you don't seem to be doing anything with it inside the loop, so at best it'll hold the last product after the loop, so is probably superfluous.
Probably you could do:
array_map([$apiSkylux->products, 'create'], $products);
or
$createdProducts = array_map([$apiSkylux->products, 'create'], $products);
depending on whether you need the return values or not.
So I can see the array has a number (28) , what does this represent?
It means it's an array with 28 elements in it.
This doesn't make any sense. Simply use the $product variable within the loop. Done!

How can I simplify a nested php array?

I'm writing a php web application where I have a nested array which looks similar to the following:
$results = array(
array(
array(
'ID' => 1,
'Name' => 'Hi'
)
),
array(
array(
'ID' => 2,
'Name' => 'Hello'
)
),
array(
array(
'ID' => 3,
'Name' => 'Hey'
)
)
);
Currently this means that when I want to use the ID field I have to call $results[0][0]['ID'] which is rather inefficient and with an array of over several hundred records becomes messy quickly. I would like to shrink the array down so that I can call $results[0]['ID'] instead.
My understanding is that a function that uses a foreach loop to iterate through each row in the array and change the format would be the best way to go about changing the format of the $results array but I am struggling to understand what to do after the foreach loop has each initial array.
Here is the code I have so far:
public function filterArray($results) {
$outputArray = array();
foreach ($results as $key => $row) {
}
return $outputArray;
}
Would anyone be able to suggest the most effective way to achieve what I am after?
Thanks :)
Simply use call_user_func_array as
$array = call_user_func_array('array_merge', $results);
print_r($array);
Demo

Remove deeply nested element from multi-dimensional array?

I need to remove an element form a deeply nested array of unknown structure (i.e. I do not know what the key sequence would be to address the element in order to unset it). The element I am removing however does have a consistent structure (stdObject), so I can search the entire multidimensional array to find it, but then it must be removed. Thoughts on how to accomplish this?
EDIT: This is the function I have right now trying to achieve this.
function _subqueue_filter_reference(&$where)
{
foreach ($where as $key => $value) {
if (is_array($value))
{
foreach ($value as $filter_key => $filter)
{
if (isset($filter['field']) && is_string($filter['field']) && $filter['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
unset($value[$filter_key]);
return TRUE;
}
}
return _subqueue_filter_reference($value);
}
}
return FALSE;
}
EDIT #2: Snipped of array structure from var_dump.
array (size=1)
1 =>
array (size=3)
'conditions' =>
array (size=5)
0 =>
array (size=3)
...
1 =>
array (size=3)
...
2 =>
array (size=3)
...
3 =>
array (size=3)
...
4 =>
array (size=3)
...
'args' =>
array (size=0)
empty
'type' => string 'AND' (length=3)
...so assuming that this entire structure is assigned to $array, the element I need to remove is $array[1]['conditions'][4] where that target is an array with three fields:
field
value
operator
...all of which are string values.
This is just a cursor problem.
function recursive_unset(&$array)
{
foreach ($array as $key => &$value) # See the added & here.
{
if(is_array($value))
{
if(isset($value['field']) && $value['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
unset($array[$key]);
}
recursive_unset($value);
}
}
}
Notes : you don't need to use is_string here, you can just make the comparison as you're comparing to a string and the value exists.
Don't use return unless you're sure there is only one occurrence of your value.
Edit :
Here is a complete example with an array similar to what you showed :
$test = array (
1 => array (
'conditions' =>
array (
0 => array ('field' => 'dont_care1', 'value' => 'test', 'operator' => 'whatever'),
1 => array ('field' => 'dont_care2', 'value' => 'test', 'operator' => 'whatever'),
2 => array ('field' => 'nodequeue_nodes_node__nodequeue_subqueue.reference', 'value' => 'test', 'operator' => 'whatever'),
3 => array ('field' => 'dont_care3', 'value' => 'test', 'operator' => 'whatever')
),
'args' => array (),
'type' => 'AND'
));
var_dump($test);
function recursive_unset(&$array)
{
foreach ($array as $key => &$value)
{
if(is_array($value))
{
if(isset($value['field']) && $value['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
unset($array[$key]);
}
recursive_unset($value);
}
}
}
recursive_unset($test);
var_dump($test);
One way to solve this was to extend your recursive function with a second parameter:
function _subqueue_filter_reference(&$where, $keyPath = array())
You'd still do the initial call the same way, but the internal call to itself would be this:
return _subqueue_filter_reference($value, array_merge($keyPath, array($key)));
This would provide you with the full path of keys to reach the current part of the array in the $keyPath variable. You can then use this in your unset. If you're feeling really dirty, you might even use eval for this as a valid shortcut, since the source of the input you'd give it would be fully within your control.
Edit: On another note, it may not be a good idea to delete items from the array while you're looping over it. I'm not sure how a foreach compiles but if you get weird errors you may want to separate your finding logic from the deleting logic.
I have arrived at a solution that is a spin-off of the function found at http://www.php.net/manual/en/function.array-search.php#79535 (array_search documentation).
Code:
function _subqueue_filter_reference($haystack,&$tree=array(),$index="")
{
// dpm($haystack);
if (is_array($haystack))
{
$result = array();
if (count($tree)==0)
{
$tree = array() + $haystack;
}
foreach($haystack as $k=>$current)
{
if (is_array($current))
{
if (isset($current['field']) && is_string($current['field']) && $current['field'] == 'nodequeue_nodes_node__nodequeue_subqueue.reference')
{
eval("unset(\$tree{$index}[{$k}]);"); // unset all elements = empty array
}
_subqueue_filter_reference($current,$tree,$index."[$k]");
}
}
}
return $tree;
}
I hate having to use eval as it SCREAMS of a giant, gaping security hole, but it's pretty secure and the values being called in eval are generated explicitly by Drupal core and Views. I'm okay with using it for now.
Anyway, when I return the tree I simply replace the old array with the newly returned tree array. Works like a charm.

Retrieve first key in multi-dimensional array using PHP

I would like to retrieve the first key from this multi-dimensional array.
Array
(
[User] => Array
(
[id] => 2
[firstname] => first
[lastname] => last
[phone] => 123-1456
[email] =>
[website] =>
[group_id] => 1
[company_id] => 1
)
)
This array is stored in $this->data.
Right now I am using key($this->data) which retrieves 'User' as it should but this doesn't feel like the correct way to reach the result.
Are there any other ways to retrieve this result?
Thanks
There are other ways of doing it but nothing as quick and as short as using key(). Every other usage is for getting all keys. For example, all of these will return the first key in an array:
$keys=array_keys($this->data);
echo $keys[0]; //prints first key
foreach ($this->data as $key => $value)
{
echo $key;
break;
}
As you can see both are sloppy.
If you want a oneliner, but you want to protect yourself from accidentally getting the wrong key if the iterator is not on the first element, try this:
reset($this->data);
reset():
reset() rewinds array 's internal
pointer to the first element and
returns the value of the first array
element.
But what you're doing looks fine to me. There is a function that does exactly what you want in one line; what else could you want?
Use this (PHP 5.5+):
echo reset(array_column($this->data, 'id'));
I had a similar problem to solve and was pleased to find this post. However, the solutions provided only works for 2 levels and do not work for a multi-dimensional array with any number of levels. I needed a solution that could work for an array with any dimension and could find the first keys of each level.
After a bit of work I found a solution that may be useful to someone else and therefore I included my solution as part of this post.
Here is a sample start array:
$myArray = array(
'referrer' => array(
'week' => array(
'201901' => array(
'Internal' => array(
'page' => array(
'number' => 201,
'visits' => 5
)
),
'External' => array(
'page' => array(
'number' => 121,
'visits' => 1
)
),
),
'201902' => array(
'Social' => array(
'page' => array(
'number' => 921,
'visits' => 100
)
),
'External' => array(
'page' => array(
'number' => 88,
'visits' => 4
)
),
)
)
)
);
As this function needs to display all the fist keys whatever the dimension of the array, this suggested a recursive function and my function looks like this:
function getFirstKeys($arr){
$keys = '';
reset($arr);
$key = key($arr);
$arr1 = $arr[$key];
if (is_array($arr1)){
$keys .= $key . '|'. getFirstKeys($arr1);
} else {
$keys = $key;
}
return $keys;
}
When the function is called using the code:
$xx = getFirstKeys($myArray);
echo '<h4>Get First Keys</h4>';
echo '<li>The keys are: '.$xx.'</li>';
the output is:
Get First Keys
The keys are: referrer|week|201901|Internal|page|number
I hope this saves someone a bit of time should they encounter a similar problem.

Categories