PHP arrays - retrieving a value when other value is known - php

I have an array of the following structure:
$some_array = array(
array(
'font' => 'Arial',
'label' => 'Arial'
),
array(
'font' => 'PT+Sans:400',
'label' => 'PT Sans'
)
);
Let's say that I only know that one item has 'font' value of 'PT+Sans:400' and I need to retrieve the 'label' value of that single item. How can I do it easier than iterating through subarrays?

Since you are already using foreach you just want other alternatives then you can consider this solutions
Solution 1
You can try to filter your search using array_filter
$search = "PT+Sans:400" ;
$array = array_filter($array,function($v)use($search){ return $v['font'] == $search;});
var_dump($array); // returns all found array
Output
array
1 =>
array
'font' => string 'PT+Sans:400' (length=11)
'label' => string 'PT Sans' (length=7)
If you need only the label
$find = array_shift($array); // take only the first
print($find['label']); // output the label
Output
PT Sans
Solution 2
It you are not interested in return the array and all you want is just the label then you should consider array_reduce
$search = "PT+Sans:400" ;
$results = array_reduce($array,function($a,$b)use($search){ return $b['font'] == $search ? $b['label'] : null ; });
print($results);
Output
PT Sans

You need to iterate through the subarrays. Alternatively, if you have control over the data structure where this is getting stored, consider using a hash table (associative array) and then you can just check if a particular key is set.

Keep it simple:
function findLabel($source, $font)
{
foreach ($source as $item) {
if ($item['font'] == $font) {
return $label;
}
}
return null;
}
Usage:
$label = findLabel($some_array, 'PT+Sans:400');

Related

Working with multidimensional array with PHP

I have this array:
$datas = array(
array(
'id' => '1',
'country' => 'Canada',
'cities' => array(
array(
'city' => 'Montreal',
'lang' => 'french'
),
array(
'city' => 'Ottawa',
'lang' => 'english'
)
)
)
);
Question 1:
How can I get the the country name when I have the id ?
I tried: $datas['id'][1] => 'country'
Question 2:
How can I loop in the cities when I have the id ?
I tried:
foreach ($datas as $data => $info) {
foreach ($info['cities'] as $item) {
echo '<li>'.$item['city'].'</li>';
}
}
Thanks a lot.
You have the ID of the array you want analyse, but your array is structured as a map, meaning that there are no keys in the outer array. You will therefore have to iterate the array first to find the object you are looking for.
While the first approach would be to search for the object that has the ID you are looking for, i suggest you map your arrays with their IDs. To do that, you can use two PHP array functions: array_column and array_combine.
array_column can extract a specific field of each element in an array. Since you have multiple country objects, we want to extract the ID from it to later use it as a key.
array_combine takes two arrays with the same size to create a new associative array. The values of the first array will then be used as keys, while the ones of the second array will be used as values.
$mappedCountries = array_combine(array_column($datas, 'id'), $datas);
Assuming that the key 1 is stored in the variable $key = 1;, you can afterwards use $mappedCountries[$key]['country'] to get the name of the country and $mappedCountries[$key]['cities'] to get the cities, over which you can then iterate.
if there might be many arrays in $datas and you want to find one by id (or some other key) you can do something like this:
function search($datas, $key, $value) {
foreach($datas as $data) {
if ($data[$key] === $value) {
return $data;
}
}
So if you want to find where id = 1
$result = search($datas, 'id', '1');
and then you can get country echo $result['country'] or whatever you need.

Php, remove key from an array red-handed

I want to remove an item from an array. I can write this:
$item = array(
'id' => 1
'name' => 'name'
);
$item2 = $item;
unset($item2['id']);
$names[] = $item2;
but the last 3 lines are somewhat "cumbersome", soo un elegant. Can it be solved without creating $item2 ? Something like:
$item = array(
'id' => 1
'name' => 'name'
);
$names[] = array_ignore_index('id', $item);
From your codes, I can see that you are trying to get the names[] from item array. One possible simple solution for this specific scenario:
For example IF you have :
$items = array(
array(
//this is your item 1
'id' => 1,
'name' => 'name1'
),
array(
//this is item 2
'id' => 2,
'name' => 'name2'
)
);
and you want to retrieve the names in the names array.
You can just do:
$names = array_column($items, 'name');
It will return:
Array
(
[0] => "name1"
[1] => "name2"
)
Please note this solution is best fit for this specific scenario, it may not fit your current scenario depending.
The shortest out of the box solution is to create a diff of the array keys:
$names[] = array_diff_key($item, array_flip(['id']));
See http://php.net/array_diff_key.
function array_ignore_index($id,$item){ ///function
unset($item[$id]);
return $item;
}
$a=array('id'=>1,
'name'=>'name');
$b=array_ignore_index('name',$a);
echo $b['name']; //create error id is not present
Here is the code for required operation..
You can use unset array column
Code is
unset($item['id']);
To test it
print_r($item);

confusing multidimensional array in php with foreach getting error

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.

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.

Understanding the basics of multidimensional arrays

I am new to using multidimensional arrays with php, I have tried to stay away from them because they confused me, but now the time has come that I put them to good use. I have been trying to understand how they work and I am just not getting it.
What I am trying to do is populate results based on a string compare function, once I find some match to an 'item name', I would like the first slot to contain the 'item name', then I would like to increment the priority slot by 1.
So when when I'm all done populating my array, it is going to have a variety of different company names, each with their respective priority...
I am having trouble understanding how to declare and manipulate the following array:
$matches = array(
'name'=>array('somename'),
'priority'=>array($priority_level++)
);
So, in what you have, your variable $matches will point to a keyed array, the 'name' element of that array will be an indexed array with 1 entry 'somename', there will be a 'priority' entry with a value which is an indexed array with one entry = $priority_level.
I think, instead what you probably want is something like:
$matches[] = array(name => 'somename', $priority => $priority_level++);
That way, $matches is an indexed array, where each index holds a keyed array, so you could address them as:
$matches[0]['name'] and $matches[0]['priority'], which is more logical for most people.
Multi-dimensional arrays are easy. All they are is an array, where the elements are other arrays.
So, you could have 2 separate arrays:
$name = array('somename');
$priority = array(1);
Or you can have an array that has these 2 arrays as elements:
$matches = array(
'name' => array('somename'),
'priority' => array(1)
);
So, using $matches['name'] would be the same as using $name, they are both arrays, just stored differently.
echo $name[0]; //'somename';
echo $matches['name'][0]; //'somename';
So, to add another name to the $matches array, you can do this:
$matches['name'][] = 'Another Name';
$matches['priority'][] = 2;
print_r($matches); would output:
Array
(
[name] => Array
(
[0] => somename
[1] => Another Name
)
[priority] => Array
(
[0] => 1
[1] => 2
)
)
In this case, could this be also a solution with a single dimensional array?
$matches = array(
'company_1' => 0,
'company_2' => 0,
);
if (isset($matches['company_1'])) {
++$matches['company_1'];
} else {
$matches['company_1'] = 1;
}
It looks up whether the name is already in the list. If not, it sets an array_key for this value. If it finds an already existing value, it just raises the "priority".
In my opinion, an easier structure to work with would be something more like this one:
$matches = array(
array( 'name' => 'somename', 'priority' => $priority_level_for_this_match ),
array( 'name' => 'someothername', 'priority' => $priority_level_for_that_match )
)
To fill this array, start by making an empty one:
$matches = array();
Then, find all of your matches.
$match = array( 'name' => 'somename', 'priority' => $some_priority );
To add that array to your matches, just slap it on the end:
$matches[] = $match;
Once it's filled, you can easily iterate over it:
foreach($matches as $k => $v) {
// The value in this case is also an array, and can be indexed as such
echo( $v['name'] . ': ' . $v['priority'] . '<br>' );
}
You can also sort the matched arrays according to the priority:
function cmp($a, $b) {
if($a['priority'] == $b['priority'])
return 0;
return ($a['priority'] < $b['priority']) ? -1 : 1;
}
usort($matches, 'cmp');
(Sourced from this answer)
$matches['name'][0] --> 'somename'
$matches['priority'][0] ---> the incremented $priority_level value
Like David said in the comments on the question, it sounds like you're not using the right tool for the job. Try:
$priorities = array();
foreach($companies as $company) {
if (!isset($priorities[$company])) { $priorities[$company] = 0; }
$priorities[$company]++;
}
Then you can access the priorities by checking $priorities['SomeCompanyName'];.

Categories