Looping php array to json prints index value - php

I have been trying to loop through an array. Inserting the values in two separate arrays $location and $name. But the $name array prints the index values as well, the $location works fine.
Here's a sample of code
$j = 0;
foreach( $entities->results as $key => $value ) {
if( stristr($value->vicinity, $key_stroke) ) {
$location[$j]['place_id'] = $value->place_id;
$location[$j]['vicinity'] = $value->vicinity;
}
if( stristr($value->name, $key_stroke) ) {
$name[$j]['place_id'] = $value->place_id;
$name[$j]['name'] = $value->name;
}
$j++; }
Here is the json output
{
"locations": [
{
"place_id": "ChIJRQqyYRFZWjcRmxKd0esyj-k",
"vicinity": "GS Road, Christian Basti, Guwahati"
},
{
"place_id": "ChIJG5IvxhNZWjcRlkMD6lCJ64c",
"vicinity": "GS Road, Ananda Nagar, Christian Basti, Guwahati"
},
{
"place_id": "ChIJxQp72BZZWjcR98oQbFrdTII",
"vicinity": "GS Road, Christian Basti, Guwahati"
},
{
"place_id": "ChIJm5eeJBBZWjcRksI_VY9u1Qo",
"vicinity": "Zoo Road, Sundarpur, Guwahati"
}
],
"names": {
"1": {
"place_id": "ChIJG5IvxhNZWjcRlkMD6lCJ64c",
"name": "Ayush Medico's"
},
"2": {
"place_id": "ChIJxQp72BZZWjcR98oQbFrdTII",
"name": "Premananda Medico's"
},
"3": {
"place_id": "ChIJm5eeJBBZWjcRksI_VY9u1Qo",
"name": "Asaan Medicos"
}
}
}
Tried everything. What could be the problem??

Solution 1: (Not efficient as the solution 2 below)
$j = 0;
$i = 0; // change over here
foreach( $entities->results as $key => $value ) {
if( stristr($value->vicinity, $key_stroke) ) {
$location[$j]['place_id'] = $value->place_id;
$location[$j]['vicinity'] = $value->vicinity;
$j++;
}
if( stristr($value->name, $key_stroke) ) {
$name[$i]['place_id'] = $value->place_id; // change over here
$name[$i]['name'] = $value->name; // change over here
$i++;
}
}
Solution 2:
Pass the $name array to php's inbuilt funtion array_values() which in turn will return you with the array index starting from 0.

If you look closely you will notice that in JSON, the value of "location" is an array but the value of "names" is an object (having the properties "1", "2" and "3"). This happens because $location is an array that contains 4 values associated with the keys 0, 1, 2 and 3 while $name is an array whose keys are 1, 2 and 3.
Because JSON is a subset of JavaScript and JavaScript arrays allow only numeric keys (starting from 0), PHP encodes as JavaScript arrays only the arrays that have numeric consecutive keys starting from 0. All the other arrays are encoded in JSON as objects.
This is written in the documentation of json_encode():
Note:
When encoding an array, if the keys are not a continuous numeric sequence starting from 0, all keys are encoded as strings, and specified explicitly for each key-value pair.
The reason why $names does not contain the key 0 is the if condition that wraps the assignment:
if( stristr($value->name, $key_stroke) ) {
The similar condition that wraps the assignment of $location[$j] can make $location behave similar with different input data.
If you want to get arrays in the JSON-encoded output you have to build them in a way that ensures the keys are consecutive integers starting with 0. This is easier than it sounds. There is no need to keep track of the keys, just build the inner arrays in a different way and let PHP generate the keys of the outer arrays:
$location = array();
$name = array();
foreach( $entities->results as $key => $value ) {
if( stristr($value->vicinity, $key_stroke) ) {
$location[] = array(
'place_id' => $value->place_id,
'vicinity' => $value->vicinity,
);
}
if( stristr($value->name, $key_stroke) ) {
$name[] = array(
'place_id' => $value->place_id,
'name' => $value->name,
);
}
}

Related

I want to get the elements that are not present in array 1 but present in array 2

I have 2 arrays.
$first = [
'01/10/2019' =>
[
21498226,
21497647,
21497649,
21497635,
21497636,
21497637,
21497728,
21497822,
21498028,
21497638,
],
];
$second = [
'01/10/2019' =>
[
21498226,
21497647,
12345678,
87654321,
21497636,
21497637,
21497728,
21497822,
21498028,
21497638,
],
];
I have written this code
$notPresent = [];
foreach ($second as $date => $code) {
foreach ($code as $c) {
if (array_key_exists($date, $first)) {
if (!in_array($c, $first[$date])) {
$notPresent[$date] = $code;
}
} else {
$notPresent[$date] = $code;
}
}
}
But it is returning me all 10 values. What I really want is to have only those values that are not present in $first. Like 12345678 and 87654321.
Swap the arrays around so that you are looking for elements of array 2 that are not in array 1, and that's word-for-word what array_diff does.
returns the values in array1 that are not present in any of the other arrays
You will need to iterate over the "parent" arrays, naturally, so array_map can help too. (Although, to preserve the keys, you'll need some fiddling around with array_keys and array_combine since array_map doesn't preserve keys...)
$notPresent = array_combine(
array_keys($second),
array_map('array_diff', $second, $first)
);
EDIT I just realised that the above code assumes that the keys exist in both arrays in the same order. Since that's almost certainly not the case, here's an adjusted version that handles that.
$notPresent = array_combine(
array_keys($second),
array_map(function($key,$values) use ($first) {
if( array_key_exists($key,$first)) {
return array_diff($values, $first[$key]);
}
return $values;
}, array_keys($second), array_values($second))
);

Peek ahead when iterating an array of arrays in PHP

I have a mysql query object result which I want to parse through. Let's say the array looks like this.
$superheroes = array(
[0] => array(
"name" => "Peter Parker",
"email" => "peterparker#mail.com",
"age"=>"33",
"sex"=>"male",
),
[1] => array(
"name" => "jLaw",
"email" => "jlaw#mail.com",
"age"=>"22",
"sex"=>"female",
),
[2] => array(
"name" => "Clark Kent",
"email" => "clarkkent#mail.com",
"age"=>"36",
"sex"=>"male",
),
[3] => array(
"name" => "Gal Gadot",
"email" => "gal#mail.com",
"age"=>"22",
"sex"=>"female",
)
);
I want to iterate through this array, and while I am at each array, I want to look ahead in the next array, and find out the age difference between current male hero and next immediate female in the list. I found a lot of posts that talk about
1. array_keys
2. caching iterators,
3. prev, next, etc.
But all of them are talking about one dimensional arrays. Here Is what I tried
foreach ($superheroes as $key => $list){
if($list['sex']=="male"){
$currentHerosAge=$list['age'];
while($next=next($superheroes)){
if($next['sex']=="female"){
$diff=$currentHerosAge -$next['age'];
echo "Age diff: ".$diff;
break;
}
}
}
}
But when I try this, for array[0], next misses the array[1], and picks up array[3]. Not sure how to work this out.
You can use array_slice to slice array form the next key index and then look for the fist female age
$diff = [];
foreach($superheroes as $key => $male) {
if ($male['sex'] === 'female' ) continue;
// get the next key index
$nextKey = $key + 1;
if ( isset( $superheroes[ $nextKey ] ) ) {
// slice from the next key index
$nextSuperHeros = array_slice($superheroes, $nextKey);
foreach($nextSuperHeros as $k => $female) {
if ($female['sex'] === 'female') {
$diff[] = $male['age'] - $female['age'];
break;
}
}
}
}
A working Example
Hope this helps
Normally, you don't use a "lookahead", when iterating over the array. The common way would be to store the item of the last iteration and do the comparison on this element
$last_hero = false;
foreach ($superheroes as $hero) {
if ($last_hero) {
// do some stuff..
}
$last_hero = $hero;
}
If you really need a lookahead of more than one item, you wouldn't use a foreach loop.
for ($i = 0; $i < count($superheroes); $i++) {
// do sth. with $superheroes[$i]
if (...) {
for ($j = $i + 1; $j < count($superheroes); $j++) {
// do sth. with $superheroes[$j]
}
}
}
this code works, here's your solution for that situation (i will update explaining why) + editing the Clark - Gal part, one more comparison.
Execute it here if you like. this is a fancy version with echo's just to illustrate the running logic and what is happening inside the loops :) of course the final result can be much more simple.
<?php
$superheroes = [
[
"name" = "Peter Parker",
"email" = "peterparker#mail.com",
"age"="33",
"sex"="male",
],[
"name" = "jLaw",
"email" = "jlaw#mail.com",
"age"="22",
"sex"="female",
],[
"name" = "Clark Kent",
"email" = "clarkkent#mail.com",
"age"="36",
"sex"="male",
],[
"name" = "Gal Gadot",
"email" = "gal#mail.com",
"age"="22",
"sex"="female",
]
];
$length = count($superheroes);
$counterReset = 0;
while ($current = current($superheroes) )
{
$length -= 1;
if($current['sex']=="male"){
$currentHerosAge = $current['age'];
while($next = next($superheroes)){
$counterReset += 1;
if($next['sex']=="female"){
$diff=$currentHerosAge - $next['age'];
echo "\n C: ".$current['name']." to ".$next['name']." Age diff: ".$diff."\n";
break;
}
}
}
if($counterReset 0){
for($i = 0; $i < $counterReset; $i++){
prev($superheroes);
}
$counterReset = 0;
}
if($length == 0){
break;
}
next($superheroes);
}
current() next() prev() all act as pointers. Which means that every time you call them you control the movement of the assuming "head" of array or element you are calling. For this reason every time you move with next() you must make sure you also return back to the desired position in order to continue looping the regular loop :)
References next(), current(), prev() and reset()
execution logic
You declaration of the array or arrays was bringing a PHP Warning PHP Warning: Illegal offset type in /home/ on line 21 and was empty. For that reason I re-declared that way.

Push static value into another array at every nth position

I have an array:
$names = [
"Ayush" , "Vaibhav", "Shivam",
"Hacker", "Topper", "ABCD",
"NameR", "Tammi", "Colgate",
"Britney", "Bra", "Kisser"
];
And I have another variable
$addthis = "ADDTHIS";
How to make an array from these two so that after every three items in $names, the value of $addthis is added. So, I want this array as result from these two.
$result = [
"Ayush", "Vaibhav", "Shivam", "ADDTHIS",
"Hacker", "Topper", "ABCD", "ADDTHIS",
"NameR", "Tammi", "Colgate", "ADDTHIS",
"Britney", "Bra", "Kisser"
];
"Oneliner", just for fun:
$new = array_reduce(
array_map(
function($i) use($addthis) { return count($i) == 3 ? array_merge($i, array($addthis)) : $i; },
array_chunk($names, 3)
),
function($r, $i) { return array_merge($r, $i); },
array()
);
Maybe an easier to understand solution:
// the parameters
$names = array( "Ayush" , "Vaibhav", "Shivam", "Hacker", "Topper",
"ABCD", "NameR", "Tammi", "Colgate", "Britney",
"Bra", "Kisser");
$addThis = 'ADDTHIS';
$every = 3;
// how often we need to add this
$count = ceil(count($names) / $every) - 1;
for ($i = 0; $i < $count; $i++) {
array_splice($names, $i * ($every + 1) + $every, 0, $addThis);
}
array_splice is exactly for modifying arrays (removing or adding items), preserves existing keys and is not doing any other operation on the array.
While other answers are for sure valid as well this should be the fastest and cleanest solution.
Another oneliner ;)
$result = call_user_func_array(
'array_merge', array_map(function($v) use ($addthis) {
return $v + [4 => $addthis];
}, array_chunk($names, 3))
); array_pop($result);
Demo
I have the ANSWER for anyone curious, I've just done a function that randomizes an array.
function randomize($array){
$randomized=array(); //start a new array
foreach ($array as $key=>$val){ ///loop thru the array we randomize
if($key % 2 == 0){ ////if the key is even
array_push($randomized,$val);///push to back
}else{ ////if the key is odd
array_unshift($randomized,$val); ///push to front
}
}
return $randomized;
}///randomize
Basically what we are doing is creating a new randomized array, looping through the array we pass, tracking an interator and as we loop thru if the key is even we send that array value to the back, if its odd we send that to the front.
I concur with #iRaS's answer that it will be more direct/efficient to make iterated element insertions in a loop. I interpret the question as requiring an element to be inserted after every 10 elements -- in other words, if the array has exactly 20 elements, then 2 elements should be inserted. One after the 10nth element, then one after the 20th element.
By iterating from the back of the array, you can avoid keeping track of previously injected elements (which effectively push out the desired position of subsequently injected elements). I didn't use this approach while crafting a dynamic approach for a similar question.
Use a modulus-based calculation to determine the last insertion position, then decrement the position variable by the $every variable.
To test the accuracy of my snippet, just add and remove elements in the input array.
Code: (Demo)
$names = [
"Ayush" , "Vaibhav", "Shivam",
"Hacker", "Topper", "ABCD",
"NameR", "Tammi", "Colgate",
"Britney"//, "Bra"//, "Kisser"
];
$addThis = 'ADDTHIS';
$every = 3;
for (
$count = count($names), $pos = $count - ($count % $every);
$pos > 0;
$pos -= $every
) {
array_splice($names, $pos, 0, $addThis);
}
var_export($names);
Output:
array (
0 => 'Ayush',
1 => 'Vaibhav',
2 => 'Shivam',
3 => 'ADDTHIS',
4 => 'Hacker',
5 => 'Topper',
6 => 'ABCD',
7 => 'ADDTHIS',
8 => 'NameR',
9 => 'Tammi',
10 => 'Colgate',
11 => 'ADDTHIS',
12 => 'Britney',
)
P.S. If you don't want to add the extra tail element (the array shouldn't end with an "ADDTHIS" element), then use this code as the first parameter of the for():
$count = count($names), $pos = $count - (($count % $every) ?: $every);
$result = array();
$cnt = 0;
foreach ($names AS $val) {
$result[] = $val;
if ($cnt >=3) {
$result[] = $addthis;
$cnt = 0;
}
$cnt++;
}
Loop through and use modulo for checking for 3. element:
After that use splice to insert an element between two element
foreach($result as $k=>$value){
if(($k+1)%3==0){
array_splice($arrayvariable, $k+1, 0, "ADDTHIS");
}
}
One thing you do not want to do is assume that every key in your array is numeric and that it accurately represents the offset of each element. This is wrong, because PHP arrays are not like traditional arrays. The array key is not the offset of the element (i.e. it does not determine the order of elements) and it does not have to be a number.
Unfortunately, PHP arrays are ordered hashmaps, not traditional arrays, so the only way to insert a new element in the middle of the map is to create a brand new map.
You can do this by using PHP's array_chunk() function, which will create a new array of elements, each containing up to a designated number of elements, form your input array. Thus we create an array of arrays or chunks of elements. This way you can iterate over the chunks and append them to a new array, getting your desired effect.
$names = array( "Ayush" , "Vaibhav", "Shivam", "Hacker", "Topper",
"ABCD", "NameR", "Tammi", "Colgate", "Britney",
"Bra", "Kisser");
$addthis = "ADDTHIS";
$result = array();
foreach (array_chunk($names, 3) as $chunk) { // iterate over each chunk
foreach ($chunk as $element) {
$result[] = $element;
}
// Now push your extra element at the end of the 3 elements' set
$result[] = $addthis;
}
If you wanted to preserve keys as well you can do this....
$names = array( "Ayush" , "Vaibhav", "Shivam", "Hacker", "Topper",
"ABCD", "NameR", "Tammi", "Colgate", "Britney",
"Bra", "Kisser");
$addthis = "ADDTHIS";
$result = array();
foreach (array_chunk($names, 3, true) as $chunk) { // iterate over each chunk
foreach ($chunk as $key => $element) {
$result[$key] = $element;
}
// Now push your extra element at the end of the 3 elements' set
$result[] = $addthis;
}
This perserves both order of the elements as well as keys of each element. However, if you don't care about the keys you can simply use the first example. Just be careful that numeric keys in order will cause you a problem with the second approach since the appended element in this example is assuming the next available numeric key (thus overwritten on the next iteration).

Given an array, find zero values and replace them with the average of immediately bordering values

I have an array of temperature data by hour. Some hours have zero data instead of a temp. When graphing using Google Charts, the zero causes the line graph to plummet. My temporary fix was to replace the zero values with null, causing a break in the line graph. The ideal solution would be to take the values on either side of the zero, and average them. The array is in order by hour. Help?
$array = array(
"1AM" => "65",
"2AM" => "66",
"3AM" => "68",
"4AM" => "68",
"5AM" => "68",
"6AM" => "0",
"7AM" => "70",
"8AM" => "71",
"9AM" => "71",
"10AM" => "73",
);
Here's my script replacing the 0's with nulls:
$array = array ();
foreach($parsed_json->history->observations as $key => $value) {
$temp = (int)$value->tempi;
if ($temp==0) {
str_replace(0, null, $temp);
}
$hour = $value->date->hour;
$array[$hour] = $temp;
};
This Example would work great if the data was mine, but alas, it's from a JSON feed.
Would I use an array_walk() sort of deal? How would I reference the current place in the array? Any help is appreciated!
I would scratch out the null portion, and just foreach-loop through the final array.
So, change your current code to:
$array = array ();
foreach($parsed_json->history->observations as $key => $value) {
$temp = (int)$value->tempi;
}
$hour = $value->date->hour;
$array[$hour] = $temp;
And add this below it:
foreach($array as $hour => $temp){
if($temp == "0"){
$numHour = $hour[0];
$hourPlus = ($numHour + 1) . "AM";
$hourMinus = ($numHour - 1) . "AM";
$valuePlus = $array[$hourPlus];
$valueMinus = $array[$hourMinus];
$average = ($valuePlus + $valueMinus)/2;
$array[$hour] = $average;
}
}
?>
This of course assumes that the values on either side of the zero are also not zero. You may want to add a check for that somewhere in there.
Tested and proven method.
Couldn't you do something along the lines of:
str_replace(0, ((($key-1)+($key+1))/2), $temp);
Where $key is array position, take the value before 0 and after 0 add them and divide them by 2 to get the average.
I'll let you sort out what happens if first, last or consecutive values are 0.
$the_keys=array_keys($array);
foreach($the_key as $index=>$key)
{
if($array[$key]==0)
{
$array[$key]=($array[$the_key[$index-1]]+$array[$the_key[$index+1]]/2);
}
}

PHP: Getting to a key in mulitdimensional array?

I have an array like
$myArray =array
(
"0"=>array("dogs",98),
"1"=>array("cats",56),
"2"=>array("buffaloes",78)
)
How can I get a key by providing a value?
e.g. if i search for "buffaloes" array_search may return "2".
Thanks
$myArray =array
(
"0"=>array("dogs",98),
"1"=>array("cats",56),
"2"=>array("buffaloes",78)
);
function findInArray($term, $array) {
foreach($array as $key => $val) {
if(in_array($term, $val, true)) {
return $key;
}
}
}
echo findInArray('buffaloes', $myArray); // 2
echo findInArray(78, $myArray); // 2
function asearch($key, $myArray) {
for ($i = 0; $i < sizeof($myArray); $i++) {
if ($myArray[$i][0] == $key) {
return $i;
}
}
return -1; # no match
}
Though, you'd probably want to restructure your array to:
$myarray = array(
'dogs' => 98,
'cats' => 56,
'buffaloes' => 78
);
And just do:
$myArray['buffaloes']; # 78
The only way you can do it is to iterate over every item and preform a Linear Search
$i = -1;
foreach ($myArray as $key => $item){
if ( $item[0] == 'buffaloes' ){
$i = $key;
break;
}
}
//$i now holds the key, or -1 if it doesn't exist
As you can see, it is really really inefficient, as if your array has 20,000 items and 'buffaloes' is the last item, you have to make 20,000 comparisons.
In other words, you need to redesign your data structures so that you can look something up using the key, for example a better way may be to rearrange your array so that you have the string you are searching for as the key, for example:
$myArray['buffaloes'] = 76;
Which is much much faster, as it uses a better data structure so that it only has to at most n log n comparisons (where n is the number of items in the array). This is because an array is in fact an ordered map.
Another option, if you know the exact value of the value you are searching for is to use array_search
I never heard of built in function. If you want something more general then above solutions you shold write your own function and use recursion. maybe array_walk_recursive would be helpful
You can loop over each elements of the array, testing if the first element of each entry is equal to "buffaloes".
For instance :
foreach ($myArray as $key => $value) {
if ($value[0] == "buffaloes") {
echo "The key is : $key";
}
}
Will get you :
The key is : 2
Another idea (more funny ?), if you want to whole entry, might be to work with array_filter and a callback function that returns true for the "bufalloes" entry :
function my_func($val) {
return $val[0] == "buffaloes";
}
$element = array_filter($myArray, 'my_func');
var_dump($element);
Will get you :
array
2 =>
array
0 => string 'buffaloes' (length=9)
1 => int 78
And
var_dump(key($element));
Gves you the 2 you wanted.

Categories