Get Value from Array as Array Key - php

How do I recursively get value from array where I need to explode a key?
I know, it's not good the question, let me explain.
I got an array
[
"abc" => "def",
"hij" => [
"klm" => "nop",
"qrs" => [
"tuv" => "wxy"
]
]
]
So, inside a function, I pass:
function xget($section) {
return $this->yarray["hij"][$section];
}
But when I want to get tuv value with this function, I want to make section as array, example:
To get hij.klm value (nop), I would do xget('klm'), but to get hij.klm.qrs.tuv, I can't do xget(['qrs', 'tuv']), because PHP consider $section as key, and does not recursively explode it. There's any way to do it without using some ifs and $section[$i] ?

function xget($section) {
return $this->yarray["hij"][$section];
}
that one is static function right?
you can do that also for this
function xget($section) {
if(isset($this->yarray["hij"][$section])){
return $this->yarray["hij"][$section];
}elseif(isset($this->yarray["hij"]["klm"]["qrs"][$section])){
return $this->yarray["hij"]["klm"]["qrs"][$section];
}
}
as long as the key name between two of them are not the same.

You could use array_walk_recursive to find tuv's value regardless of the nested structure:
$tuv_val='';
function find_tuv($k,$v)
{
global $tuv_val;
if ($k=='tuv')
$tuv_val=$v;
}
array_walk_recursive($this->yarray,"find_tuv");
echo "the value of 'tuv' is $tuv_val";

try my code
<?php
$array = array(
'aaa' => 'zxc',
'bbb' => 'asd',
'ccc' => array(
'ddd' => 'qwe',
'eee' => 'tyu',
'fff' => array(
'ggg' => 'uio',
'hhh' => 'hjk',
'iii' => 'bnm',
),
),
);
$find = '';
function xget($key){
$GLOBALS['find'] = $key;
$find = $key;
array_walk_recursive($GLOBALS['array'],'walkingRecursive');
}
function walkingRecursive($value, $key)
{
if ($key==$GLOBALS['find']){
echo $value;
}
}
xget('ggg');
?>

Related

Arrange Array in PHP

How can I sort the array ["Name":"OVERALL"] always last in the array element. This array ["Name":"OVERALL"] always on index 1. I think my current method is not a really good implementation. Is there any better ways?
[
["Name":"AHMAD SUFFIAN BIN AHMAD LOTFI","SLAData":[0,0,0,0,0,0],"RatingData":[0,0,0,0,0,0]],
["Name":"OVERALL","SLAData":[19,8,50,0,0,100],"RatingData":[95,95,100,0,0,0]],
["Name":"JAYALETCHUMI A\/P VENGADASALAM","SLAData":[33,14,100,0,0,0],"RatingData":[90,90,100,0,0,0]],
["Name":"MOHAMMAD FIRDHAUS BIN ISMAIL","SLAData":[0,0,0,0,0,0],"RatingData":[100,100,0,0,0,0]],
["Name":"YOGESWARAN A\/L PUSSAN","SLAData":[0,0,0,0,0,0],"RatingData":[0,0,0,0,0,0]],
["Name":"JAYAKUMAR PARAMASIVAM","SLAData":[0,0,0,0,0,100],"RatingData":[0,0,0,0,0,0]]
]
This is my current method
$Temp=[];
$output = array_slice($MonthlyData, 1, 1);
foreach ($MonthlyData as $data) {
if($data['Name']!='OVERALL')
$Temp[] = $data;
}
}
$Temp[] = $output;
$MonthlyData = $Temp;
There's multiple ways to do this. I chose a way that doesn't require changing the code you provided much. All this code does is add the elements to a front of a temprary array unless it is the one you want to be last. That one it puts on the end of the array.
$MonthlyData = [
["Name" => "AHMAD SUFFIAN BIN AHMAD LOTFI","SLAData" => [0,0,0,0,0,0],"RatingData" => [0,0,0,0,0,0]],
["Name" => "OVERALL","SLAData" => [19,8,50,0,0,100],"RatingData" => [95,95,100,0,0,0]],
["Name" => "JAYALETCHUMI A\/P VENGADASALAM","SLAData" => [33,14,100,0,0,0],"RatingData" => [90,90,100,0,0,0]],
["Name" => "MOHAMMAD FIRDHAUS BIN ISMAIL","SLAData" => [0,0,0,0,0,0],"RatingData" => [100,100,0,0,0,0]],
["Name" => "YOGESWARAN A\/L PUSSAN","SLAData" => [0,0,0,0,0,0],"RatingData" => [0,0,0,0,0,0]],
["Name" => "JAYAKUMAR PARAMASIVAM","SLAData" => [0,0,0,0,0,100],"RatingData" => [0,0,0,0,0,0]]
];
$Temp=[];
foreach ($MonthlyData as $data) {
if ($data['Name'] === 'OVERALL') {
$Temp[] = $data;
}
else {
array_unshift($Temp, $data);
}
}
$MonthlyData = $Temp;
Demo
If you want a more concise way to do it, use usort() to sort based on a specified criteria. In this case, always put an array last if it's "name" value is "OVERALL".
usort($MonthlyData, static function ($a, $b) {
return ($a['Name'] === 'OVERALL') ? 1 : -1;
});
Demo

Laravel collection remove all keys if in any of them has value NULL

For some calculation i need to remove all keys in whole collection if he has in any array NULL value.
for example
[
'butter'=>['iron'=>5, 'magnesium'=>3.5],
'salt'=>['iron'=>2, 'magnesium'=>2],
'egg'=>['iron'=>4, 'magnesium'=>NULL]
]
Because one of item is empty i need new array to be like this
[
'butter'=>['iron'=>5],
'salt'=>['iron'=>2],
'egg'=>['iron'=>4]
]
I'm not sure i can accomplish this with Laravel collection, maybe there is better way with pure php.
P.S. Sorry my english is not so good
I think your approach is reasonable but if you want to explore other solution here it is:
public function index()
{
$foods = [
'butter' => ['iron' => 5, 'magnesium' => 3.5, 'calcium' => 3],
'salt' => ['iron' => 2, 'magnesium' => 2, 'calcium' => 6],
'egg' => ['iron' => 4, 'magnesium' => NULL, 'calcium' => 5]
];
$newFoods = $this->removeNullKeys($foods);
echo '<pre>';
print_r($newFoods);die;
}
public function removeNullKeys(array $array): array
{
$innerKeys = array_keys(current($array));
$toRemove = array_reduce($innerKeys, function ($carry, $key) use ($array) {
if (in_array(null, array_column($array, $key), true)) {
$carry[$key] = null;
}
return $carry;
}, []);
return array_map(function ($e) use ($toRemove) {
return array_diff_key($e, $toRemove);
}, $array);
}
the result will be:
Array
(
[butter] => Array
(
[iron] => 5
[calcium] => 3
)
[salt] => Array
(
[iron] => 2
[calcium] => 6
)
[egg] => Array
(
[iron] => 4
[calcium] => 5
)
)
I hope it helps.
OK i make this code and this work like i want, but i think its ugly is there some better way with Laravel collection or in pure php
$foods=[
'butter'=>['iron'=>5, 'magnesium'=>3.5, 'calcium'=>3],
'salt'=>['iron'=>2, 'magnesium'=>2, 'calcium'=>6],
'egg'=>['iron'=>4, 'magnesium'=>NULL, 'calcium'=>5]
];
$nutrientsWithNull=[];
foreach($foods as $food)
{
foreach($food as $key=>$value){
if(is_null($value)&&!in_array($key, $nutrientsWithNull))
{
$nutrientsWithNull[]=$key;
}
}
}
foreach($foods as $key=>$food)
{
foreach($nutrientsWithNull as $withNull ) {
unset($foods[$key][$withNull]);
}
}
print_r($foods);
and result is
$foods=[
'butter'=>['iron'=>5, 'calcium'=>3],
'salt'=>['iron'=>2, 'calcium'=>6],
'egg'=>['iron'=>4, 'calcium'=>5]
];

PHP: How to create a good foreach shorthand?

I have a simple object (or array) like this...
stdClass Object (
[people] => Array
(
[0] => stdClass Object (
[name] => 'John',
[age] => 50,
)
[0] => stdClass Object (
[name] => 'Martin',
[age] => 47,
)
)
And I can easily loop through it using foreach like this
foreach ($people as $person) {
echo $person->name . '<br>';
}
But I would somehow like to have a shorter way to echo all names with something like this...
print_each($people->name)
And it would do exactly the same thing with only 1 short line of code as my 3 lines of foreach code did.
Is there a function like this or how would we go about creating a function like that?
You can use array_column and implode.
echo implode("<br>\n", array_column($arr, "name"));
Probably array_map is the closest to what you want.
array_map(function($person) { echo $person->name; }, $people);
Shortest way and not that ugly would be to add a
__toString
Method to the Person Object like this:
class Person {
public $name;
public function __toString()
{
return (string) $this->name;
}
}
This then enables you to use the very super short:
array_walk($people, 'printf');
Syntax.
If you have array, you can use array_column for that:
$people = [
['name' => 'John', 'age' => 3],
['name' => 'Carl', 'age' => 43]
];
var_dump(
array_column($people, 'name')
);
/*
array(2) {
[0]=>
string(4) "John"
[1]=>
string(4) "Carl"
}
Since PHP 7.4 you can do:
echo implode('', array_map(fn($person) => $person->name . '<br>', $people));
The inner array_map() function takes as second parameter your initial array $people.
The inner array_map() function takes as first parameter an arrow function fn() => that gets the single items $person out of your initial array $people
inside the arrow function each $person->name gets concated with '<br>' and written as value in a new array.
this new array will be returned by the array_map() function
The items of this array will be passed as second parameter to the implode() function and glued together with the empty string ''.
the entire string that implode() returns gets echoed out
If you want to get "smart" about it you can write something like this:
array_walk_recursive($a, function($v, $k) {echo $k === 'name' ? $v : '';});
But being smart over readability is a bad idea, always.
If I had to write a function to do that, it would be something along these lines:
function print_each($collection, $property) {
foreach ($collection as $item) {
echo $item->$property . "<br />";
}
}
Which could be used like so:
$people = [
(object)[
"name" => "Bob",
"age" => 25
],
(object)[
"name" => "Dan",
"age" => 31
],
(object)[
"name" => "Sally",
"age" => 45
]
];
print_each($people, "name"); // prints "Bob<br />Dan<br />Sally<br />"

PHP Compare and change certain elements in multidimensional arrays

To be short, I have two simple arrays and I want to verify if certain keys from the second array have empty values and replace them with their correspondent values from the first array.
Example:
$a1 = [ 1 => 'one', 2 => 'two', 3 => 'three',5=>'cinco', 6=>'six'];
$a2 = [ 2 => 'two', 5=>'five', 6=>'' ];
Result:
Array
(
[2] => two
[5] => five
[6] => six
)
The following code works already for this.
$keys = array_keys($a1);
foreach ($keys as $k)
{
if ((isset($a2[$k])) && (($a2[$k]) == '')) {
$a2[$k] = $a1[$k];
}
}
print_r($a2);
But what if we want to apply this for two 2D arrays? What will be the proper approach in that case? Let's say these two 2D arrays will be:
$superheroes_complete = array(
"spiderman" => array(
"name" => "Peter Parker",
"email" => "peterparker#mail.com",
),
"superman" => array(
"name" => "Clark Kent",
"email" => "clarkkent#mail.com",
),
"ironman" => array(
"name" => "Harry Potter",
"email" => "harrypotter#mail.com",
)
);
$superheroes_empty = array(
"spiderman" => array(
"name" => "Peter Parker",
"email" => "",
),
"superman" => array(
"name" => "Clark Kent",
"email" => "something",
),
"ironman" => array(
"name" => "Harry Potter",
"email" => "another one",
)
);
Expectation:
$superheroes = array(
"spider-man" => array(
"name" => "Peter Parker",
"email" => "peterparker#mail.com",
),
"super-man" => array(
"name" => "Clark Kent",
"email" => "something",
),
"iron-man" => array(
"name" => "Harry Potter",
"email" => "another one",
)
);
Much appreciation and thank you in advance!
You've added another level to your data, so you can just add another level to your checking as well with a second foreach loop:
foreach ($superheroes_complete as $hero => $info) {
foreach ($info as $key => $value) {
if (empty($superheroes_empty[$hero][$key])) {
$superheroes_empty[$hero][$key] = $value;
}
}
}
First note that your 1D case can be simplified:
foreach ($a2 as $k => $v) {
if (!isset($v)) {
$a2[$k] = $a1[$k];
}
}
Then for the 2D case, assuming the 1st level keys are always the same (or it becomes a quite different question!):
foreach ($superheroes_complete as $main_k => $main_v) {
foreach ($main_v as $k => $v) {
if (!isset($v)) {
$superheroes_empty[$main_k][$k] = $superheroes_complete[$main_k][$k];
}
}
If you only need to take care of the "email" field you can do this :
<?php
$keys = array_keys($superheroes_complete);
foreach ($keys as $k)
{
if ((isset($superheroes_empty[$k]["email"])) &&
(($superheroes_empty[$k]["email"]) == '')) {
$superheroes_empty[$k]["email"] = $superheroes_complete[$k]["email"];
}
}
var_dump($superheroes_empty);
?>
For the generic case where the depth of nesting is unlimited, you could use this recursive function:
function fillEmpty(&$filled, &$empty) { // arguments are by reference
if ($empty === "") {
$empty = $filled;
return;
}
if (!is_array($filled) || !is_array($empty)) return;
foreach ($filled as $key => $value) {
if (isset($empty[$key])) fillEmpty($value, $empty[$key]);
}
}
Example call:
fillEmpty($superheroes_complete, $superheroes_empty);
This modifies the second argument, filling the empty values.
See it run on eval.in
It might be your lucky day, php has some built in functions to compare arrays values and keys. Use array_diff() which can compare two or more arrays and return the difference. You could also use array_intersect() which does the opposite.
If you want to only compare the keys, use array_diff_key()which returns only the key difference or array_intersect_key() which returns the matched keys.
You could also consider a recursive solution. This could work on both the 1D and 2D arrays, or even an array of N dimensions.
I'm aware that recursion should be used with care, as it can be quite resource intensive. This is however a more versatile solution, and keeps the code cleaner with less nested control structures and early returns, which I find better readable. I'll use the native array_walk method because I was taught that it should perform better then a php loop.
So this is what my code would look like:
function array_complement_recursive(&$partial, $complete) {
array_walk($partial, function(&$value, $key) use ($complete) {
// (for safety) complete does not contain matching key: done
if (! array_key_exists($key, $complete)) {
return;
}
// value is array: call recursive
if (is_array($value)) {
array_complement_recursive($value, $complete[$key]);
return;
}
// value is not 'empty': done
// note that null, 0, false will also not match, you may want to make
// this check more specific to match only the empty string
if ($value) {
return;
}
$value = $complete[$key];
});
}
I've set up a little demo so you can see that it works on both your examples. And as I said, it should even work for arrays with more dimensions, or a more irregular structure.
http://phpfiddle.org/main/code/49iz-vrwg
I've added some comments to explain, but feel free to ask if anything is unclear.

PHP Find a value in a key and get the value of another key in a multi-dimentional array

Might be a newbie question but I've been trying to figure this problem and it's doing my head in.
I have the following array :
[0] => Array
(
[provisionalBookingRoomID] => 1
[totalSpecificRoomCount] => 2
)
[1] => Array
(
[provisionalBookingRoomID] => 2
[totalSpecificRoomCount] => 5
)
I need a php function that searches through the array for the value of 'provisionalBookingRoomID' and returns the value of 'totalSpecificRoomCount'
basically something like the following
getProvisionalTotalRoomsCount($currentRoom, $arrayOfRooms);
// getProvisionalTotalRoomsCount('1', $arrayOfRooms) should return 2;
Any ideas?
Check this:
getProvisionalTotalRoomsCount($currentRoom, $arrayOfRooms){
foreach($arrayOfRooms as $key=>$value){
if($value['provisionalBookingRoomID'] == $currentRoom){
return $value['totalSpecificRoomCount'];
}
}
}
For anyone looking for a generic function :
function findValueInArray($array, $searchValue, $searchKey, $requiredKeyValue) {
foreach($array as $key=>$value){
if($value[$searchKey] == $searchValue){
return $value[$requiredKeyValue];
}
}
}
// Usage : findValueInArray($provisionalBookedRoomsArray, '1', 'provisionalBookingRoomID', 'totalSpecificRoomCount');
If you are likely to work with more than one value, you could build a new array with a 1->1 map for those attributes.
<?php
$items = array(
array(
'name' => 'Foo',
'age' => 23
),
array(
'name' => 'Bar',
'age' => 47
)
);
// Php 7
$name_ages = array_column($items, 'name', 'age');
echo $name_ages['Foo']; // Output 23
// Earlier versions:
$name_ages = array();
foreach($items as $value)
{
$name_ages[$value['name']] = $value['age'];
}
echo $name_ages['Foo']; // Output 23
$value = 0;
$array = array(array("provisionalBookingRoomID"=>1,"totalSpecificRoomCount"=>2),array("provisionalBookingRoomID"=>2,"totalSpecificRoomCount"=>5));
array_map(
function($arr) use (&$value) {
if($arr['provisionalBookingRoomID']==1) {
$value = $arr['totalSpecificRoomCount'];
}
},$array
);
echo $value;

Categories