I'm working on PHP array iteration. I have arrays for example as below :
1) banned 2) age
$banned = array(
"school_name"=> "abc",
"school_rating"=> "xyz",
);
$age = array(
"Peter"=> "35", // 0
"Ben"=> "16", // 1
"Joe"=> "43" // 2
"john"=> "12", // 3
);
I'm iterating over this array using foreach :
foreach($age as $index => $value) {
if ($value < '18') {
$banned['name_' . $index] = $value; // Push values below 18 to 'banned' array with index value
}
}
I want to find names which are below age 18 & push theme to 'banned' array.
This code works correct. But while pushing names to 'banned' array, I want to append new index to their names such as 'Ben_0' 'john_1'.
Current code appending index as per foreach iteration such as 'Ben_1' 'john_3'.
I want my final array to like :
$banned = array(
"school_name"=> "abc",
"school_rating"=> "xyz",
"Ben_0"=> "16",
"john_1"=> "12",
);
I want this new indexing in order to perform some API call later.
So is there any way to achieve this ?
You mean something like:
$count = 0;
foreach($age as $index => $value) {
if ($value < '18') {
$banned[$index . '_' . $count++] = $value; // Push values below 18 to 'banned' array with index value
}
}
You can do it like this:
$i = 0;
foreach($age as $index => $value)
{
if ($value < '18') {
$banned['name_' . $i] = $value; // Push values below 18 to 'banned' array with index value
$i++;
}
}
$i = 0;
foreach ($age as $name => $age)
{
$banned[$name . '_' . $i++] = $age;
}
Related
I have an array that looks like this.
$array = [
0 => 'abc',
1 => [
0 => 'def',
1 => 'ghi'
],
'assoc1' => [
'nassoc' => 'jkl',
'nassoc2' => 'mno',
'nassoc3' => '',
'nassoc4' => false
]
];
The $array can have numeric keys or be an assoc array or a mixed one. The level of nesting is not known. Also the values of the array can also be bool or null or an empty string ''
I need to able to convert this into a scalar array with key value pairs. And then later reconvert it back to the exact same array.
So the scalar array could look like
$arrayScalar = [
'0' => 'abc',
'1[0]' => 'def',
'1[1]' => 'ghi',
'assoc1[nassoc]' => 'jkl',
'assoc1[nassoc2]' => 'mno',
'assoc1[nassoc3]' => '',
'assoc1[nassoc4]' => false
];
And then later be able to get back to the initial $array.
I wrote a parser and it does not currently handle bool values correctly.
I have a feeling this is at best a super hacky method to do what I am after. Also I have been able to test it only so much.
function flattenNestedArraysRecursively($nestedArray, $parent = '', &$flattened = [])
{
$keys = array_keys($nestedArray);
if (empty($keys)) {
$flattened[$parent] = 'emptyarray';
} else {
foreach ($keys as $value) {
if (is_array($nestedArray[$value])) {
$reqParent = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$this->flattenNestedArraysRecursively($nestedArray[$value], $reqParent, $flattened);
} else {
$reqKey = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$flattened[$reqKey] = $nestedArray[$value];
}
}
}
return $flattened;
}
function reCreateFlattenedArray($flatArray): array
{
$arr = [];
foreach ($flatArray as $key => $value) {
$keys = explode('|!|', $key);
$arr = $this->reCreateArrayRecursiveWorker($keys, $value, $arr);
}
return $arr;
}
function reCreateArrayRecursiveWorker($keys, $value, $existingArr)
{
//Outside to Inside
$keyCur = array_shift($keys);
//Check if keyCur Exists in the existingArray
if (key_exists($keyCur, $existingArr)) {
// Check if we have reached the deepest level
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// If not then continue to go deeper while appending deeper levels values to current key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, $existingArr[$keyCur]);
return $existingArr;
}
} else {
// If Key does not exists in current Array
// Check deepest
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// Add the key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, []);
return $existingArr;
}
}
}
Is there a better more elegant way of doing this, maybe http_build_query or something else I am not aware of.
Sandbox link -> http://sandbox.onlinephpfunctions.com/code/50b3890e5bdc515bc145eda0a1b34c29eefadcca
Flattening:
Your approach towards recursion is correct. I think we can make it more simpler.
We loop over the array. if the value is an array in itself, we recursively make a call to this new child subarray.
This way, we visit each key and each value. Now, we are only left to manage the keys to assign them when adding to our final resultant array, say $arrayScalar.
For this, we make a new function parameter which takes the parent key into account when assigning. That's it.
Snippet:
$arrayScalar = [];
function flatten($array,&$arrayScalar,$parent_key){
foreach($array as $key => $value){
$curr_key = empty($parent_key) ? $key : $parent_key . '[' . $key . ']';
if(is_array($value)){
flatten($value,$arrayScalar,$curr_key);
}else{
$arrayScalar[$curr_key] = $value;
}
}
}
flatten($array,$arrayScalar,'');
var_export($arrayScalar);
Demo: http://sandbox.onlinephpfunctions.com/code/1e3092e9e163330f43d495cc9d4acb672289a987
Unflattening:
This one is a little tricky.
You might have already noticed that the keys in the flattened array are of the form key1[key2][key3][key4] etc.
So, we collect all these individually in a new array, say $split_key. It might look like this.
array (
'key1',
'key2',
'key3',
'key4',
)
To achieve the above, we do a basic string parsing and added in-between keys to the array whenever we reach the end of the key string or [ or ].
Next, to add them to our final resultant array, we loop over the collected keys and check if they are set in our final array. If not so, set them. We now pass child array reference to our temporary variable $temp. This is to edit the same copy of the array. In the end, we return the result.
Snippet:
<?php
function unflatten($arrayScalar){
$result = [];
foreach($arrayScalar as $key => $value){
if(is_int($key)) $key = strval($key);
$split_key = [];
$key_len = strlen($key);
$curr = '';
// collect them as individual keys
for($i = 0; $i < $key_len; ++$i){
if($key[ $i ] == '[' || $key[ $i ] == ']'){
if(strlen($curr) === 0) continue;
$split_key[] = $curr;
$curr = '';
}else{
$curr .= $key[ $i ];
}
if($i === $key_len - 1 && strlen($curr) > 0){
$split_key[] = $curr;
}
}
// collecting them ends
//add them to our resultant array.
$temp = &$result;
foreach($split_key as $sk){
if(!isset($temp[ $sk ])){
$temp[ $sk ] = [];
}
$temp = &$temp[$sk];
}
$temp = $value;
}
return $result;
}
var_export(unflatten($arrayScalar));
Demo: http://sandbox.onlinephpfunctions.com/code/66136a699c3c5285eed3d3350ed4faa5bbce4b76
I have this array in PHP:
$items = array(
array(
"info" => "This is my info",
"colors" => array(
"type" => "block",
array(
"name" => "Red",
"ref" => "red"
),
array(
"name" => "Blue",
"ref" => "blue"
),
),
),
);
I want to loop into the color array like this:
foreach ($items as $item) {
foreach ($item['colors'] as $color) {
$color['name'];
}
}
The problem, is the first result is b from block.
How can I change this behavior ?
Thanks.
You can check whether the name element exists in the $color value:
foreach ($items as $item) {
foreach ($item['colors'] as $color) {
if (isset($color['name'])) {
$name = $color['name'];
// do something with it
}
}
}
For the given array, reference the keys in your first loop to get to colors and check if the $value is an array, if it is, then check to see if the array_key name is in the array, if it is, you have the value(s) you are looking for.
// assuming you know the array levels design your conditional to check if you have an array - is_array, if you do, make sure the target key is in_array, if it is, compare the target key with the values array_keys and then echo the value['target_key']
foreach($items[0]['colors'] as $value){
if(is_array($value)){
if(in_array('name', array_keys($value))){
echo $value['name'].'<br>';
}
}
}
// slightly more dynamic way to use incrementor,
// though this assumes you still know the level of 'colors' and 'name'
$i = count($items);
for($j = 0; $j < $i; $j++){
foreach($items[$j]['colors'] as $value){
if(is_array($value)){
if(in_array('name', array_keys($value))){
echo $value['name'].'<br>';
}
}
}
}
// or check each level to see if is array and if target key is in array
$i = count($items);
for($j = 0; $j < $i; $j++){
foreach($items[$j] as $value){
if(is_array($value)){
if(in_array('colors', array_keys($value))){
foreach($value as $color){
if(is_array($color)){
if(in_array('name', array_keys($color))){
echo $color['name'];
}
}
}
}
}
}
}
Each iteration will output:
Red
Blue
i will ask how to insert array if amount sub arrays not same, i have problem if the $arrays != 3 because in sub arrays 2 in arrays one
<?php
$arrays=array(
array('a','b'),
array('a','b','c'),
array('a','b','c')
);
$per=0;
for ($h=0; $h < count($arrays); $h++) {
if (count($arrays) > $per) {
$per= count($arrays);
}
}
$koneksi = new mysqli("127.0.0.1","root","","data");
$nil=array();
foreach ($arrays as $data) {
foreach ($data as $key => $value) {
$data[$key] = $data[$key];
}
$nil[]="('".implode("', '",$data). "')";
}
$insert="INSERT INTO datams (data1,data2,data3) VALUES ".implode(', ',$nil);
$queri=mysqli_query($koneksi, $insert);
if ($queri == true){
echo 'upload done'.PHP_EOL;
} else {
echo 'fail upload'.PHP_EOL;
}
i can't insert the data if sub array same, can help me ?
You will have to make the arrays the same length.
Create an empty array, then loop your existing array, adding the missing values using array_replace. After that, you can insert them.
$empty=['' , '' , ''];
foreach($array as $key => $tmp){
$array[$key] = array_replace($empty,$tmp);
// This replaces the values of $empty with those of $array that are set:
// ['','',''] replace wihh ['a','b','c'] gives ['a','b','c']
// ['','',''] replace with ['a','b'] gives ['a','b','']
}
You will end up with:
$arrays=array(
array('a','b','' ),
array('a','b','c'),
array('a','b','c')
);
Now you can insert the values;
EDIT
To make it more flexible (i.e the original array keeps changing), you first have to find the length of the longest array in $array.
$max=0;
foreach($array as $a) {
$c = count($a);
if( $c > $max) $max = $c;
}
$empty=array_fill(0,$max,'');
( Full pastebin: https://pastebin.com/C4qV5YYv)
I'm trying to select data from a (long) multi dimensional array, but with all things I tried the page just showed as blank. I'm trying to access the data with the name instead of it's rank in the list.
{
"playerstats": {
"steamID": "76561198035223060",
"gameName": "ValveTestApp260",
"stats": [
{
"name": "total_kills",
"value": 38694
},
{
"name": "total_deaths",
"value": 33362
},
{
"name": "total_time_played",
"value": 2148546
},
{
"name": "total_planted_bombs",
"value": 770
},
{
"name": "total_defused_bombs",
"value": 271
},
{
"name": "total_wins",
"value": 12394
}, So on and so on......
I'm currently using this to get data from the array: $kills = $jsonforgame['playerstats']['stats'][0]['value'];
This works when you only need a couple of values, but it gets really tidy when I need to select values further down, like; $hit = $jsonforgame['playerstats']['stats'][47]['value'];
Is there anyway for me to select the stats with the name, like this: $hit = $jsonforgame['playerstats']['stats']['total_shots_fired']['value']; instead of the number.
Thanks in advance.
You may go for something like this:
function getStat($data, $name)
{
return array_filter($data, function($item) use ($name) {
return $item && $item['name'] === $name;
})[0]['value'];
}
$hit = getStat($jsonforgame['playerstats']['stats'], 'total_shots_fired');
But the more efficient way would be to change your stats api so it serves key-value pairs, if it is possible, ofc.
One way would be to change how you create the array as so:
{
"playerstats": {
"steamID": "76561198035223060",
"gameName": "ValveTestApp260",
"stats":
{
"total_kills": 38694,
"total_deaths": 33362,
"total_time_played": 2148546,
...
}
then simply access by $kills = $jsonforgame['playerstats']['stats']['total_kills']
In case you can't change the array, you could also try
$specs = array("total_kills", "total_deaths", "total_time_played"); // and so on
foreach ( $specs as $spec )
$$spec = $jsonforgame['playerstats']['stats'][ $spec ]['value'];
After that you can use each spec by name, for example $total_kills
If you want to use shorter variable names you can change the code like this
$specs = array(
"kills" => "total_kills",
"died" => "total_deaths",
"played" => "total_time_played"
); // and so on
foreach ( $specs as $key => $spec )
$$key = $jsonforgame['playerstats']['stats'][ $spec ]['value'];
echo $kills; // output $jsonforgame['playerstats']['stats']['total_kills']['value']
Another approach
$count = count($jsonforgame['playerstats']['stats']);
for ( $i = 0; $i < $count; $i++ ) {
$name = $jsonforgame['playerstats']['stats'][ $i ]['name'];
$value = $jsonforgame['playerstats']['stats'][ $i ]['value'];
$$name = $value;
}
and with use of the array with shorter variable names
$specs = array(
"total_kills" => "kills",
"total_deaths" => "died",
"total_time_played" => "played",
); // and so on
$count = count($jsonforgame['playerstats']['stats']);
for ( $i = 0; $i < $count; $i++ ) {
$name = $specs[ $jsonforgame['playerstats']['stats'][ $i ]['name'] ];
$value = $jsonforgame['playerstats']['stats'][ $i ]['value'];
$$name = $value;
}
I know how to iterate an array in PHP, but I want to iterate an array from a specific key.
Assume that I have a huge array
$my_array = array(
...
...
["adad"] => "value X",
["yy"] => "value Y",
["hkghgk"] => "value Z",
["pp"] => "value ZZ",
...
...
)
I know the key where to start to iterate ("yy"). Now I want to iterate only from this key to another key.
I know that I don't want to do this:
$start_key = "yy";
foreach ($my_array as $key => $v)
{
if ($key == $start_key)
...
}
I was looking for Iterator, but I don't think this is what I need.
Try combining array_search, array_key, and LimitIterator. Using the example from the LimitIterator page and some extra bits:
$fruitsArray = array(
'a' => 'apple',
'b' => 'banana',
'c' => 'cherry',
'd' => 'damson',
'e' => 'elderberry'
);
$startkey = array_search('d', array_keys($fruitsArray));
$fruits = new ArrayIterator($fruitsArray);
foreach (new LimitIterator($fruits, $startkey) as $fruit) {
var_dump($fruit);
}
Starting at position 'd', this outputs:
string(6) "damson" string(10) "elderberry"
There is a limit to this approach in that it won’t loop around the array until the start position again. It will only iterate to the end of an array and then stop. You would have to run another foreach to do the first part of the array, but that can be easily done with the code we already have.
foreach (new LimitIterator($fruits, 0, $startkey-1) as $fruit) {
var_dump($fruit);
}
This starts from the first element, up to the element before the one we searched for.
foreach always resets the array's array pointer. You just can't do that the way you imagine.
You still have a few ways. The foreach way is just skipping everything until you found the key once:
$start_key = "yy";
$started = false;
foreach ($my_array as $key => $v)
{
if ($key == $start_key) {
$started = true;
}
if (!$started) {
continue;
}
// your code
}
You could as well work with the array pointer and use the while (list($key, $v) = each($array)) method:
$start_key = "yy";
reset($array); // reset it to be sure to start at the beginning
while (list($key, $v) = each($array) && $key != $start_key); // set array pointer to $start_key
do {
// your code
} while (list($key, $v) = each($array));
Alternatively, you can just extract the array you want to iterate over like MarkBaker proposed.
Perhaps something like:
foreach(array_slice(
$my_array,
array_search(
$start_key,array_keys($my_array)
),
null,
true) as $key => $v) {}
Demo
You can use array_keys and array_search.
Like this:
$keys = array_keys( $my_array ); // store all of your array indexes in a new array
$position = array_search( "yy" ,$keys ); // search your starting index in the newly created array of indexes
if( $position == false ) exit( "Index doesn't exist" ); // if the starting index doesn't exist the array_search returns false
for( $i = $position; $i < count( $keys ); $i++ ) { // starting from your desired index, this will iterate over the rest of your array
// do your stuff to $my_array[ $keys[ $i ] ] like:
echo $my_array[ $keys[ $i ] ];
}
Try it like this:
$startkey = array_search('yy', array_keys($my_array));
$endkey = array_search('zz', array_keys($my_array));
$my_array2 = array_values($my_array);
for($i = $startkey; $i<=$endkey; $i++)
{
// Access array like this
echo $my_array2[$i];
}
If this pull request makes it through, you will be able to do this quite easily:
if (seek($array, 'yy', SEEK_KEY)) {
while ($data = each($array)) {
// Do stuff
}
}