Need to get all the age keys and count the number of them greater than 50. Given data
$data = '{"data":"key=IAfpK, age=58, key=WNVdi, age=64, key=jp9zt, age=47"}';
Output should be 2 as there are 2 ages greater than 50
This is what I am trying
$array = json_decode($data, true);
$strArray = explode(',', $array['data']);
$temp1 = array();
for($i=0; $i < count($strArray); $i++){
$key_value = explode('=', $strArray[$i]);
$temp1[$i][$key_value[0]] = $key_value[1];
}
print "<pre>";
print_r($temp1);
print "</pre>";
Output is coming as
Array
(
[0] => Array
(
[key] => IAfpK
)
[1] => Array
(
[ age] => 58
)
[2] => Array
(
[ key] => WNVdi
)
[3] => Array
(
[ age] => 64
)
[4] => Array
(
[ key] => jp9zt
)
[5] => Array
(
[ age] => 47
)
)
Need to get all the ages in an array to compare.
If your data is truly semi-structured like that and isn’t too massive, and you want to keep the keys, I think this is a good case for array_shift to reduce the array until it is exhausted:
$data = '{"data":"key=IAfpK, age=58, key=WNVdi, age=64, key=jp9zt, age=47"}';
$array = json_decode($data, true);
$strArray = explode(',', $array['data']);
$clean = [];
while(count($strArray) >= 2){
$key = explode('=', array_shift($strArray))[1];
$age = explode('=', array_shift($strArray))[1];
$clean[$key] = (int)$age;
}
var_dump($clean);
Demo: https://3v4l.org/RIF2q
You should hopefully be able to add whatever logic you need to test ages then.
Short and simple. Hope this will work for you,
$output = [];
$data = '{"data":"key=IAfpK, age=58, key=WNVdi, age=64, key=jp9zt, age=47"}';
$array = json_decode($data, true);
foreach (explode(',',$array['data']) as $key => $value)
{
if(str_contains($value,'age'))
{
$age = explode('=',$value);
if($age[1] > 50)
{
array_push($output, $age[1]);
}
}
}
print_r($output);
An effective way to achieve this since your data is strangely formatted would be to use regex. For some reason, the ?: non capturing group is still being captured so all of the ages will be in the second capture group of the match array - you can play to optimise that.
Once you have all your ages in an array, a simple array_filter for ages larger than 50 is more than enough. You can see a live working example on 3v4l.org.
$data = '{"data":"key=IAfpK, age=58, key=WNVdi, age=64, key=jp9zt, age=47"}';
preg_match_all('/(?:age=)([0-9]+)/', json_decode($data)->data, $matches, PREG_PATTERN_ORDER);
// Only continue if we found any ages in the string
if (array_key_exists(1, $matches))
{
// 58, 64
$greaterThan50 = array_filter($matches[1], fn($age) => intval($age) > 50);
}
Ofc, if you then need the corresponding key, you will need to do more magic.
If you're using less than PHP 7.4, arrow functions are not supported. You can instead replace $greaterThan50 assignment to:
$greaterThan50 = array_filter($matches[1], function($age) {
return intval($age) > 50;
});
See it working live on 34vl.org
Based on your logic, You can do it as follows :
<?php
$data = '{"data":"key=IAfpK, age=58, key=WNVdi, age=64, key=jp9zt, age=47"}';
$array = json_decode($data, true);
$strArray = explode(',', $array['data']);
$keys = array();
$ages = array();
for($i=0; $i < count($strArray); $i++){
$key_value = explode('=', $strArray[$i]);
if ((int)$key_value[1] > 0 ) {
array_push($ages, $key_value[1]);
} else {
array_push($keys, $key_value[1]);
}
}
$result = array_combine($keys, $ages);
$result = array_filter($result, function($age) {
return intval($age) > 50;
});
print "<pre>";
print_r($result);
print "</pre>";
Related
PHP seperate number using based on 2 delimiter
I have this variable $sid
$sid = isset($_POST['sid']) ? $_POST['sid'] : '';
and it's output is:
Array
(
[0] => 4|1
[1] => 5|2,3
)
Now I want to get the 1, 2, 3 as value so that I can run a query based on this number as ID.
How can I do this?
Use explode()
$arr = array(
0 => "4|1",
1=> "5|2,3"
);
$output = array();
foreach($arr as $a){
$right = explode("|",$a);
$rightPart = explode(",",$right[1]);
foreach($rightPart as $rp){
array_push($output,$rp);
}
}
var_dump($output);
Use foreach to loop thru your array. You can explode each string to convert it to an array. Use only the 2nd element of the array to merge
$sid = array('4|1','5|2,3');
$result = array();
foreach( $sid as $val ) {
$val = explode('|', $val, 2);
$result = array_merge( $result, explode(',', $val[1]) );
}
echo "<pre>";
print_r( $result );
echo "</pre>";
You can also use array_reduce
$sid = array('4|1','5|2,3');
$result = array_reduce($sid, function($c, $v){
$v = explode('|', $v, 2);
return array_merge($c, explode(',', $v[1]));
}, array());
These will result to:
Array
(
[0] => 1
[1] => 2
[2] => 3
)
You can do 2 explode with loop to accomplish it.
foreach($sid as $a){
$data = explode("|", $a)[1];
foreach(explode(",", $data) as $your_id){
//do you stuff with your id, for example
echo $your_id . '<br/>';
}
}
I'm curious if it is possible to make this piece of code I've made a bit shorter and probably faster? The goal of this code below is to update the string by changing (and preserving) numbers in it with ordered replacements such as {#0}, {#1} and so on for each number found.
Also, keep that found numbers separately in array so we may recover information at any time.
The code below works but I believe it may be significantly optimized and hopefully done in one step.
$str = "Lnlhkjfs7834hfdhrf87whf4akuhf999re";//could be any string
$nums = array();
$count = 0;
$res = preg_replace_callback('/\d+/', function($match) use(&$count) {
global $nums;
$nums[] = $match[0];
return "{#".($count++)."}";
}, $str);
print_r($str); // "Lnlhkjfs7834hfdhrf87whf4akuhf999re"
print_r($res); // "Lnlhkjfs{#0}hfdhrf{#1}whf{#2}akuhf{#3}re"
print_r($nums); // ( [0] => 7834 [1] => 87 [2] => 4 [3] => 999 )
Is it possible?
$str = "Lnlhkjfs7834hfdhrf87whf4akuhf999re";//could be any string
$nums = array();
$count = 0;
$res = preg_replace_callback('/([0-9]+)/', function($match) use (&$count,&$nums) {
$nums[] = $match[0];
return "{#".($count++)."}";
}, $str);
print_r($str); // "Lnlhkjfs7834hfdhrf87whf4akuhf999re"
print_r($res); // "Lnlhkjfs{#0}hfdhrf{#1}whf{#2}akuhf{#3}re"
print_r($nums); // ( [0] => 7834 [1] => 87 [2] => 4 [3] => 999 )
After some little fixes it works. \d+ works too.
NOTE: Can not explain why global $nums; wont work. Maybe php internal issue/bug
Nothing to add to #JustOnUnderMillions answer, just an other way that avoids the callback function:
$nums = [];
$res = preg_split('~([0-9]+)~', $str, -1, PREG_SPLIT_DELIM_CAPTURE);
foreach ($res as $k => &$v) {
if ( $k & 1 ) {
$nums[] = $v;
$v = '{#' . ($k >> 1) . '}';
}
}
$res = implode('', $res);
Not shorter, but faster.
[
{"category":["30","32","33"],"type":"30 days","price":"100","ID":"0"},
{"category":["34","37","47"],"type":"30 days","price":"200","ID":1},
{"category":["46"],"type":"40 days","price":"100","ID":2}
]
in the above JSON, how to get all the category which has type: 30days.
Expected Output as.
$categories = array{0=>30,1=>32,2=>33,3=>34,4=>37,4=>47}
You can use array_walk as
$json = '[
{"category":["30","32","33"],"type":"30 days","price":"100","ID":"0"},
{"category":["34","37","47"],"type":"30 days","price":"200","ID":1},
{"category":["46"],"type":"40 days","price":"100","ID":2}
]';
$arr = json_decode($json,true);
$categories = array();
array_walk($arr,function($v,$k)use(&$categories,$arr){
if($v['type'] == "30 days"){
$categories = array_merge($categories,$v['category']);
}
});
Use this:
$json = '[
{"category":["30","32","33"],"type":"30 days","price":"100","ID":"0"},
{"category":["34","37","47"],"type":"30 days","price":"200","ID":1},
{"category":["46"],"type":"40 days","price":"100","ID":2}
]';
$a = json_decode($json,true);
$categories = array();
foreach($a as $ar){
if($ar['type'] == '30 days'){
$categories = array_merge($categories,$ar['category']);
}
}
print_r($categories);
Output:
Array ( [0] => 30 [1] => 32 [2] => 33 [3] => 34 [4] => 37 [5] => 47 )
http://sandbox.onlinephpfunctions.com/code/ea84f8a5baf5c231b4e9427b3b79f16bbc075401
Just chain a bunch of transformation functions together:
$data =<<<JSON
[
{"category":["30","32","33"],"type":"30 days","price":"100","ID":"0"},
{"category":["34","37","47"],"type":"30 days","price":"200","ID":1},
{"category":["46"],"type":"40 days","price":"100","ID":2}
]
JSON;
$data = json_decode($data, true);
$x = call_user_func_array('array_merge', array_column(array_filter($data, function($row) {
return $row['type'] == '30 days';
}), 'category'));
print_r($x);
See also: array_filter() array_column() call_user_func_array()
I'm having a problem with this. I have a string that looks like this:
coilovers[strut_and_individual_components][complete_strut][][achse]
And i want to convert it to to array that looks like this:
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut]=> Array
(
[1] => Array
(
[achse] => some_value
)
[2] => Array
(
[achse] => some_value
)
)
)
)
is it possible?
Here is a quick implementation of a parser that will attempt to parse this string:
$input = 'coilovers[strut_and_individual_components][complete_strut][][achse]';
$output = array();
$pointer = &$output;
while( ($index = strpos( $input, '[')) !== false) {
if( $index != 0) {
$key = substr( $input, 0, $index);
$pointer[$key] = array();
$pointer = &$pointer[$key];
$input = substr( $input, $index);
continue;
}
$end_index = strpos( $input, ']');
$array_key = substr( $input, $index + 1, $end_index - 1);
$pointer[$array_key] = array();
$pointer = &$pointer[$array_key];
$input = substr( $input, $end_index + 1);
}
print_r( $output);
Essentially, we are iterating the string to find matching [ and ] tags. When we do, we take the value within the brackets as $array_key and add that into the $output array. I use another variable $pointer by reference that is pointing to the original $output array, but as the iteration goes, $pointer points to the last element added to $output.
It produces:
Array
(
[coilovers] => Array
(
[strut_and_individual_components] => Array
(
[complete_strut] => Array
(
[] => Array
(
[achse] => Array
(
)
)
)
)
)
)
Note that I've left the implementation of [] (an empty array key) and setting the values in the last index (some_value) as an exercise to the user.
Well I've found an another answer for it and it looks like this:
private function format_form_data(array $form_values) {
$reformat_array = array();
$matches = array();
$result = null;
foreach($form_values as $value) {
preg_match_all("/\[(.*?)\]/", $value["name"], $matches);
$parsed_product_array = $this->parse_array($matches[1], $value["value"]);
$result = array_push($reformat_array, $parsed_product_array);
}
return $result;
}
private function parse_array(array $values, $value) {
$reformat = array();
$value_carrier_key = end($values);
foreach (array_reverse($values) as $arr) {
$set_value_carrier = array($arr => $reformat);
if($arr == $value_carrier_key) {
$set_value_carrier = array($arr => $value);
}
$reformat = empty($arr) ? array($reformat) : $set_value_carrier;
}
return $reformat;
}
where array $form_values is:
Array
(
[name] => '[coilovers][strut_and_individual_components][complete_strut][][achse]',
[value] => 'some_value'
)
No. If you evaluate the string you will get invalid PHP.
If you want to store a PHP Array as string and get it loaded back as PHP Array, have a look at serialize and unserialize functions.
Of course you can build an array from your string, but you'll have to write a parser.
The solution I propose:
function format_form_data(array $data) {
$matches = array();
$result = [];
foreach($data as $key => $value) {
preg_match_all("/\[(.*?)\]/", $key, $matches);
$matches = array_reverse($matches[1]);
$matches[] = substr( $key, 0, strpos($key, '['));;
foreach ($matches as $match) {
$value = [$match=>$value];
}
$result = array_replace_recursive($result, $value);
}
return $result;
}
I have the following Arrays:
$front = array("front_first","front_second");
$inside = array("inside_first", "inside_second", "inside_third");
$back = array("back_first", "back_second", "back_third","back_fourth");
what I need to do is combine it so that an output would look like this for the above situation. The output order is always to put them in order back, front, inside:
$final = array(
"back_first",
"front_first",
"inside_first",
"back_second",
"front_second",
"inside_second",
"back_third",
"front_second",
"inside_third",
"back_fourth",
"front_second",
"inside_third"
);
So basically it looks at the three arrays, and whichever array has less values it will reuse the last value multiple times until it loops through the remaining keys in the longer arrays.
Is there a way to do this?
$front = array("front_first","front_second");
$inside = array("inside_first", "inside_second", "inside_third");
$back = array("back_first", "back_second", "back_third","back_fourth");
function foo() {
$args = func_get_args();
$max = max(array_map('sizeof', $args)); // credits to hakre ;)
$result = array();
for ($i = 0; $i < $max; $i += 1) {
foreach ($args as $arg) {
$result[] = isset($arg[$i]) ? $arg[$i] : end($arg);
}
}
return $result;
}
$final = foo($back, $front, $inside);
print_r($final);
demo: http://codepad.viper-7.com/RFmGYW
Demo
http://codepad.viper-7.com/xpwGha
PHP
$front = array("front_first", "front_second");
$inside = array("inside_first", "inside_second", "inside_third");
$back = array("back_first", "back_second", "back_third", "back_fourth");
$combined = array_map("callback", $back, $front, $inside);
$lastf = "";
$lasti = "";
$lastb = "";
function callback($arrb, $arrf, $arri) {
global $lastf, $lasti, $lastb;
$lastf = isset($arrf) ? $arrf : $lastf;
$lasti = isset($arri) ? $arri : $lasti;
$lastb = isset($arrb) ? $arrb : $lastb;
return array($lastb, $lastf, $lasti);
}
$final = array();
foreach ($combined as $k => $v) {
$final = array_merge($final, $v);
}
print_r($final);
Output
Array
(
[0] => back_first
[1] => front_first
[2] => inside_first
[3] => back_second
[4] => front_second
[5] => inside_second
[6] => back_third
[7] => front_second
[8] => inside_third
[9] => back_fourth
[10] => front_second
[11] => inside_third
)
Spreading the column data from multiple arrays with array_map() is an easy/convenient way to tranpose data. It will pass a full array of elements from the input arrays and maintain value position by assigning null values where elements were missing.
Within the custom callback, declare a static cache of the previously transposed row. Iterate the new transposed row of data and replace any null values with the previous rows respective element.
After transposing the data, call array_merge(...$the_transposed_data) to flatten the results.
Code: (Demo)
$front = ["front_first", "front_second"];
$inside = ["inside_first", "inside_second", "inside_third"];
$back = ["back_first", "back_second", "back_third", "back_fourth"];
var_export(
array_merge(
...array_map(
function(...$cols) {
static $lastSet;
foreach ($cols as $i => &$v) {
$v ??= $lastSet[$i];
}
$lastSet = $cols;
return $cols;
},
$back,
$front,
$inside
)
)
);
Output:
array (
0 => 'back_first',
1 => 'front_first',
2 => 'inside_first',
3 => 'back_second',
4 => 'front_second',
5 => 'inside_second',
6 => 'back_third',
7 => 'front_second',
8 => 'inside_third',
9 => 'back_fourth',
10 => 'front_second',
11 => 'inside_third',
)