Related
I have this array written below, and I know it isnt pretty, sorry. I come to this array structure as it is the only way I could think of when dealing with my post request.
$_POST = array("person" => array(
[1] => array("id" => 1, "name" => "bob"),
[2] => array("id" => 2, "name" => "jim")
)
);
I want to be able to pick "name" from certain "id", so below code is what I came up with. In the example below, if person["id"] is equal to 1, retrieve its "name" which is "bob".
foreach ($_POST as $dataSet) {
foreach ($dataSet as $person) {
foreach ($person as $field => $value) {
if ($person["id"] == 1) {
echo $person["name"];
}
}
}
}
The problem I am having is as I execute the code.
the result is bobbob,
it seems like the code looped the if statement twice (same as the number of elements in the person array). I know if I put break into the code, then it will solve it, but anyone know why it looped twice? Maybe this will deepen my foreach and array understanding.
There is no need to have third nested loop. Hope this one will be helpful.
Problem: In the third loop you were iterating over Persons: array("id" => 1, "name" => "bob") which have two keys. and you are checking only single static key $person["id"], that's why it was printing twice.
Solution 1:
Try this code snippet here
<?php
ini_set('display_errors', 1);
$POSTData = array("person" => array(
1 => array("id" => 1, "name" => "bob"),
2 => array("id" => 2, "name" => "jim")
)
);
foreach ($POSTData as $dataSet)
{
foreach ($dataSet as $person)
{
if ($person["id"] == 1)
{
echo $person["name"];
}
}
}
Solution 2:
Alternatively you can try this single line solution.
Try this code snippet here
echo array_column($POSTData["person"],"name","id")[1];//here 1 is the `id` you want.
You must have seen the other answers, and they have already said that you dont need the 3rd loop. but still if you want to keep the third loop.
you can use this code.
foreach ($_POST as $dataSet) {
foreach ($dataSet as $person) {
foreach ($person as $field => $value) {
if($value == 1){
echo $person['name'];
}
}
}
}
No need of third foreach
<?php
$mainArr = array("person" => array(
1 => array("id" => 1, "name" => "bob"),
2 => array("id" => 2, "name" => "jim")
)
);
foreach ($mainArr as $dataSet) {
foreach ($dataSet as $person) {
if ($person["id"] == 1) {
echo $person["name"];
break;
}
}
}
?>
Live demo : https://eval.in/855386
Although it's unclear why you need to do a POST in this fashion, here's how to get "bob" only once:
<?php
$_POST = array("person" => array(
1 => array("id" => 1, "name" => "bob"),
2 => array("id" => 2, "name" => "jim")
)
);
$arr = array_pop($_POST);
foreach($arr as $a) {
if ($a["id"] == 1) {
echo $a["name"];
}
}
Array_pop() is useful for removing the first element of the array whose value is an array itself which looks like this:
array(2) {
[1]=>
array(2) {
["id"]=>
int(1)
["name"]=>
string(3) "bob"
}
[2]=>
array(2) {
["id"]=>
int(2)
["name"]=>
string(3) "jim"
}
}
When the if conditional evaluates as true which occurs only once then the name "bob" displays.
See live code.
Alternatively, you could use a couple of loops as follows:
foreach ($_POST["person"] as $data) {
foreach ($data as $value) {
if ( $value == 1) {
echo $data["name"],"\n";
}
}
}
See demo
As you mentioned, I want to be able to pick name from certain id, : No need of nested looping for that. You can do like this using array_column and array_search :
$data = array("person" => array(
1 => array("id" => 1, "name" => "bob"),
2 => array("id" => 2, "name" => "jim")
)
);
// 1 is id you want to search for
$key = array_search(1, array_column($data['person'], 'id'));
echo $data['person'][$key + 1]['name']; // $key + 1 as you have started array with 1
Output:
bob
with foreach:
foreach ($data as $dataValue) {
foreach ($dataValue as $person) {
if ($person['id'] === 1) {
echo $person["name"];
}
}
}
How can I obtain a key in a array just by knowing it's value? For example, here is an array:
$array = Array("Item1" => array("Number" => "One", "Letter" => "A"));
Just by knowing "One" or "A", how can I get the main key name, Item1?
I've looked into array_key_value and in_array but I do not think that those functions are helpful for my kind of array.
Since it is a 2d array, you will want to search the inner array for the value so you would have to make your own function to do this. Something like this:
function findInArray($array, $lookup){
//loop over the outer array getting each key and value.
foreach($array as $key=>$value){
//if we found our lookup value in the inner array
if(in_array($lookup, $value)){
//return the original key
return $key;
}
}
//else, return null because not found
return null;
}
$array = Array("Item1" => array("Number" => "One", "Letter" => "A"));
var_dump(findInArray($array, 'One')); //outputs string(5) "Item1"
var_dump(findInArray($array, 'Two')); //outputs null
Demo: https://3v4l.org/oRjHK
This function may help you
function key_of_value($array, $value){
foreach($array as $key=>$val){
if(in_array($value, $val)){
return $key;
}
}
return null;
}
echo key_of_value(['Item1'=>['One','Two','Three','Hello',2,6]],'A');
There is no way around iterating through your data. This might be a little more elegant than two foreach loops:
<?php
$match = null;
$needle = 'Two';
$haystack = [
'Item1' => [
'Number' => 'One',
'Letter' => 'A'
],
'Item2' => [
'Number' => 'Two',
'Letter' => 'B'
],
'Item3' => [
'Number' => 'Three',
'Letter' => 'C'
],
];
array_walk($haystack, function($entry, $key) use ($needle, &$match) {
if(in_array($needle, $entry)) {
$match = $key;
}
});
var_dump($match);
The output obviously is:
string(5) "Item2"
You can use array_walk_recursive to iterate on array values recursive. I write a function that return main key of searched value in nested arrays.
<?php
$array = array("Item1" => array("Number" => "One", "Letter" => "A", 'other' => array('Number' => "Two")));
echo find_main_key($array, 'One'); //Output: "Item1"
echo find_main_key($array, 'A'); //Output: "Item1"
echo find_main_key($array, 'Two'); //Output: "Item1"
var_dump(find_main_key($array, 'nothing')); // NULL
function find_main_key($array, $value) {
$finded_key = NULL;
foreach($array as $this_main_key => $array_item) {
if(!$finded_key) {
array_walk_recursive($array_item, function($inner_item, $inner_key) use ($value, $this_main_key, &$finded_key){
if($inner_item === $value) {
$finded_key = $this_main_key;
return;
}
});
}
}
return $finded_key;
}
This is how I would do it:
foreach($array as $key => $value) {
if(in_array('One', $value)) echo $key;
}
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.
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
I am sure that this is super easy and built-in function in PHP, but I have yet not seen it.
Here's what I am doing for the moment:
foreach($array as $key => $value) {
echo $key; // Would output "subkey" in the example array
print_r($value);
}
Could I do something like the following instead and thereby save myself from writing "$key => $value" in every foreach loop? (psuedocode)
foreach($array as $subarray) {
echo arrayKey($subarray); // Will output the same as "echo $key" in the former example ("subkey"
print_r($value);
}
Thanks!
The array:
Array
(
[subKey] => Array
(
[value] => myvalue
)
)
You can use key():
<?php
$array = array(
"one" => 1,
"two" => 2,
"three" => 3,
"four" => 4
);
while($element = current($array)) {
echo key($array)."\n";
next($array);
}
?>
Use the array_search function.
Example from php.net
$array = array(0 => 'blue', 1 => 'red', 2 => 'green', 3 => 'red');
$key = array_search('green', $array); // $key = 2;
$key = array_search('red', $array); // $key = 1;
$foo = array('a' => 'apple', 'b' => 'ball', 'c' => 'coke');
foreach($foo as $key => $item) {
echo $item.' is begin with ('.$key.')';
}
$array = array(0 => 100, "color" => "red");
print_r(array_keys($array));
If it IS a foreach loop as you have described in the question, using $key => $value is fast and efficient.
If you want to be in a foreach loop, then foreach($array as $key => $value) is definitely the recommended approach. Take advantage of simple syntax when a language offers it.
Another way to use key($array) in a foreach loop is by using next($array) at the end of the loop, just make sure each iteration calls the next() function (in case you have complex branching inside the loop)
Try this
foreach(array_keys($array) as $nmkey)
{
echo $nmkey;
}
Here is a generic solution that you can add to your Array library. All you need to do is supply the associated value and the target array!
PHP Manual: array_search() (similiar to .indexOf() in other languages)
public function getKey(string $value, array $target)
{
$key = array_search($value, $target);
if ($key === null) {
throw new InvalidArgumentException("Invalid arguments provided. Check inputs. Must be a (1) a string and (2) an array.");
}
if ($key === false) {
throw new DomainException("The search value does not exists in the target array.");
}
return $key;
}