JSON - Get average from values in php - php

I made a search but no success. I always get some error...
What I want is, get the average of the values "Import" grouped by date.
I appreciate if someone can help me...
My JSON file:
[
{
"Date": "2019-03",
"Import": "200",
"Export": "50"
},
{
"Date": "2019-03",
"Import": "800",
"Export": "200"
},
{
"Date": "2019-04",
"Import": "100",
"Export": "600"
}
]
My PHP Script:
$url = dirname(__DIR__ ) . '/admin/json/all.json';
$json = file_get_contents($url);
$array_origin = json_decode($json, TRUE);
$stack=array();
foreach ($array_origin as $v) {
$stack[$v['Date']]['Import'] = isset($v['Date']) ? $stack[$v['Date']]['Import'] + $v['Import'] : $v['Import'];
$stack[$v['Date']]['Export'] = isset($v['Date']) ? $stack[$v['Date']]['Export'] + $v['Export'] : $v['Export'];
$stack[$v['Date']]['Average_Import'] = 'GET HERE AVERAGE';
}
echo '<pre>' . var_export($stack, true) . '</pre>';
Thanks in advance.
Cheers

What I want is, get the average of the values "Import"
Simple
$array_origin = json_decode('[
{
"Date": "2019-03",
"Import": "200",
"Export": "50"
},
{
"Date": "2019-03",
"Import": "800",
"Export": "200"
},
{
"Date": "2019-04",
"Import": "100",
"Export": "600"
}
]', true);
echo round(array_sum(array_column($array_origin, 'Import'))/count($array_origin));
Output
367
Sandbox
This is an aggregate value of all the rows, so it doesn't make much sense to store it in each of the rows.
If not all rows have the Import you can just make the column a variable and count that instead:
$import = array_column($array_origin, 'Import'); //["200","800","100"]
echo round(array_sum($import)/count($import));
UPDATE
While this wasn't clear
No, because as you see, have a filter "by date". You are printing all itens, not by date. :( –
It's still a trivial problem (once you know how many items there are and the total).
$stack = [];
foreach ($array_origin as $v) {
$key = $v['Date'];
if(!isset($stack[$key])) $stack[$key] = [];
$stack[$key]['Import'] = isset($stack[$key]['Import']) ? $stack[$key]['Import'] + $v['Import'] : $v['Import'];
$stack[$key]['Export'] = isset($stack[$key]['Export']) ? $stack[$key]['Export'] + $v['Export'] : $v['Export'];
//track the number of items
$stack[$key]['items'] = isset($stack[$key]['items'] ) ? ++$stack[$key]['items'] : 1;
$stack[$key]['Average_Import'] = 'GET HERE AVERAGE';
}
//cant average tell you know what they are, this will have to be done after the foreach
array_walk($stack,function(&$item){
$item['Average_Import'] = $item['Export']/$item['items'];
return $item;
});
print_r ($stack);
Output
Array
(
[2019-03] => Array
(
[Import] => 1000
[Export] => 250
[items] => 2
[Average_Import] => 125
)
[2019-04] => Array
(
[Import] => 100
[Export] => 600
[items] => 1
[Average_Import] => 600
)
)
Additionally, this foreach loop was just littered with issues, so I fixed them up. Mostly little things...
For example:
isset($v['Date']) ? $stack[$v['Date']]['Import'] + $v['Import']
This does nothing to prevent read errors from addition, for this value ['Import']. This isset($v['Date']) can be true all day long and that tells us nothing about if $stack[$v['Date']]['Import'] is set or not. If it's not set and we try to read it for addition (have to know its value to add to it) we will get a notice for undefined index.
Sandbox
Now If you don't want to track those item counts ( for whatever reason )
This is a nice trick (plus its fun) to get the number of items for a given date:
$num_dates = array_count_values(array_column($array_origin, 'Date'));
Output
Array
(
[2019-03] => 2
[2019-04] => 1
)
That will give you that information, Then use $num_dates in the callback (literally, pun intended) and the key of the item:
foreach ($array_origin as $v) {
$key = $v['Date'];
if(!isset($stack[$key])) $stack[$key] = [];
$stack[$key]['Import'] = isset($stack[$key]['Import']) ? $stack[$key]['Import'] + $v['Import'] : $v['Import'];
$stack[$key]['Export'] = isset($stack[$key]['Export']) ? $stack[$key]['Export'] + $v['Export'] : $v['Export'];
$stack[$key]['Average_Import'] = 'GET HERE AVERAGE';
}
$num_dates = array_count_values(array_column($array_origin, 'Date'));
array_walk($stack,function(&$item,$key)use($num_dates){
//may want to check if $key exists (but it should always)
$item['Average_Import'] = $item['Export']/$num_dates[$key];
return $item;
});
Output
Array
(
[2019-03] => Array
(
[Import] => 1000
[Export] => 250
[Average_Import] => 125
)
[2019-04] => Array
(
[Import] => 100
[Export] => 600
[Average_Import] => 600
)
)
Sandbox

$array_origin = json_decode('[
{
"Date": "2019-03",
"Import": "200",
"Export": "50"
},
{
"Date": "2019-03",
"Import": "800",
"Export": "200"
},
{
"Date": "2019-04",
"Import": "100",
"Export": "600"
}
]', true);
$counts = [];
$imports = [];
foreach ($array_origin as $data) {
if (isset($data['Import']) && isset($data['Date'])) {
if (!isset($counts[$data['Date']])) {
$counts[$data['Date']] = 0;
$imports[$data['Date']] = 0;
}
$counts[$data['Date']]++;
$imports[$data['Date']] = intval($data['Import']) + $imports[$data['Date']];
}
}
$importAverage = [];
foreach ($imports as $date => $importSum) {
$importAverage[$date] = $importSum > 0 ? $importSum / $counts[$date] : 0;
}
var_dump($importAverage);
array (size=2)
'2019-03' => int 500
'2019-04' => int 100

Related

Get all max values from array of objects in php

I have this array of objects i'm getting from query in mysql, i need th
[
{
"id": "11",
"from_userid": "1996",
"contest_id": "29",
"to_userid": "8",
"vote_date": "2020-10-06 01:40:04",
"count_votes": "1"
},
{
"id": "1",
"from_userid": "82",
"contest_id": "29",
"to_userid": "94",
"vote_date": "2020-09-03 07:06:36",
"count_votes": "1"
},
{
"id": "2",
"from_userid": "82",
"contest_id": "29",
"to_userid": "98",
"vote_date": "2020-09-03 07:06:36",
"count_votes": "0"
}
]
I need the object which has highest 'count_votes ' for eg- id-11 and 1 have similar count votes. So the function should return those 2 objects.
The function i am using returns only one object. I need both of the objects whichever maybe but the highest(count_votes) objects.
Expected Output-
[
{
"id": "11",
"from_userid": "1996",
"contest_id": "29",
"to_userid": "8",
"vote_date": "2020-10-06 01:40:04",
"count_votes": "1"
},
{
"id": "1",
"from_userid": "82",
"contest_id": "29",
"to_userid": "94",
"vote_date": "2020-09-03 07:06:36",
"count_votes": "1"
}
]
Function used-
function max_attribute_in_array($array, $prop) {
return max(array_map(function($o) use($prop) {
return $o;
},
$array));
}
And tried this also-
function get_highest($arr) {
$max = $arr[0]; // set the highest object to the first one in the array
foreach($arr as $obj) { // loop through every object in the array
$num = $obj['count_votes']; // get the number from the current object
if($num > $max['count_votes']) { // If the number of the current object is greater than the maxs number:
$max = $obj; // set the max to the current object
}
}
return $max; // Loop is complete, so we have found our max and can return the max object
}
You can use array_column to extract all the count_votes values into an array, which you can then take the max of:
$max = max(array_column($arr, 'count_votes'));
You can then array_filter your array based on the count_votes value being equal to $max:
$out = array_filter($arr, function ($o) use ($max) {
return $o['count_votes'] == $max;
});
Output:
Array
(
[0] => Array
(
[id] => 11
[from_userid] => 1996
[contest_id] => 29
[to_userid] => 8
[vote_date] => 2020-10-06 01:40:04
[count_votes] => 1
)
[1] => Array
(
[id] => 1
[from_userid] => 82
[contest_id] => 29
[to_userid] => 94
[vote_date] => 2020-09-03 07:06:36
[count_votes] => 1
)
)
Demo on 3v4l.org
NOTE max works with single level arrays, so all your objects are converted to int's internally.
As #Nick has pointed out your get_highest can be done via PHP functions:
function get_highest($array, $prop) {
return max(array_column($array, $prop));
}
So all you have to do is filter your array by this get_highest:
$max = get_highest($myArray, 'count_votes');
$maxes = array_filter($myArray, fn($obj) => $obj['count_votes'] === $max);
function get_heighest($arr){
$newArray = array();
$voteCount = 0;
foreach($arr as $obj){
if($obj['count_votes'] >= $voteCount){
array_push($newArray, $obj)
$voteCount = $obj['count_votes'];
}else{
$i = 0;
foreach($newArray as $object){
if($object['count_votes'] < $voteCount){
unset($newArray[$i]);
}
$i++;
}
}
}
return $newArray;
}

JSON - Sum values by date using php

I'm creating a simple script in php and json, however I have some difficulties to make Sums of multi values by date.
I want Sum "Import" and "Export" from each month.
This is what I want to print:
array (
'Date' => '2019-03',
'Import' => 1000,
'Export' => 250,
)
array (
'Date' => '2019-04',
'Import' => 100,
'Export' => 600,
)
My json:
[
{
"Date": "2019-03",
"Import": "200",
"Export": "50"
},
{
"Date": "2019-03",
"Import": "800",
"Export": "200"
},
{
"Date": "2019-04",
"Import": "100",
"Export": "600"
}
]
This is my script php:
$url = dirname(__DIR__ ) . '/admin/json/all.json';
$json = file_get_contents($url);
$array_origin = json_decode($json, TRUE);
$stack=array();
foreach ($array_origin as $index => $array_part) {
$stack[$array_part['Date']] =array_key_exists($array_part['Date'],$stack)?$stack[$array_part['Date']]+$array_part['Import']:$array_part['Import'];
}
echo '<pre>' . var_export($stack, true) . '</pre>';
However with this script Im only able to Sum 'Import', but I want also Sum 'export'.
For that reason Im looking for your help.
I appreciate for any help from you guys.
Thanks in advance.
Cheers
You need to add Import and Export keys to the result array. I've attempted to shorten it and used isset:
foreach ($array_origin as $v) {
$stack[$v['Date']]['Import'] = isset($v['Date']) ? $stack[$v['Date']]['Import'] + $v['Import'] : $v['Import'];
$stack[$v['Date']]['Export'] = isset($v['Date']) ? $stack[$v['Date']]['Export'] + $v['Export'] : $v['Export'];
}

Merge multi-dimensional arrays and sum column values which share a common value in another column

I have 3 arrays for storing posts,comments, and likes.
These are the JSON strings:
//comments JSON (stores user and comment points)
$comments='[
{
"user": "5",
"points": "12"
},
{
"user": "2",
"points": "1"
},
{
"user": "3",
"points": "1"
}
]';
//likes(stores user and likes point)
$likes='[
{
"user": "1",
"points": 7
},
{
"user": "4",
"points": 4
},
{
"user": "3",
"points": 1
}
]';
//posts (stores user and post points)
$posts='[
{
"user": "1",
"points": "6"
},
{
"user": "3",
"points": "2"
},
{
"user": "2",
"points": "1"
}
]';
I convert these JSONs into arrays like this:
$comment_array = json_decode($comments,TRUE);
$like_array = json_decode($likes,TRUE);
$post_array = json_decode($posts,TRUE);
//echo '<pre>';
//print_r($comment_array);
//print_r($like_array);
//print_r($post_array);
//echo '</pre>';
Now, I'm trying to sum these points and save the result in a new array. It's not mandatory that a user should have entries in all the three arrays. It depends on whether a user has made a comment, post or like.
function mergeArrays($filenames, $titles, $descriptions) {
$result = array();
foreach ( $filenames as $key=>$name ) {
$result[] = array( 'filename' => $name, 'title' => $titles[$key], 'descriptions' => $descriptions[ $key ] );
}
return $result;
}
The above function can merge all the three arrays.
$merged= mergeArrays($comment_array, $like_array, $post_array);
echo '<pre>';
print_r($merged);
echo '</pre>';
However, each array after merging is stored as an index element.
How can I get a result something like this:
$result='[
{
"user": "1",
"points": "13"
},
{
"user": "2",
"points": "2"
},
{
"user": "3",
"points": "4"
},
{
"user": "4",
"points": "4"
},
{
"user": "5",
"points": "12"
}
]';
Considering your three arrays, this code will get you an array with: points, votes and diferent users.
Edit: Adding additional array and printing it to get the output desired by question.
$points = 0;
$uniqueUsers = array();
$votes = 0;
$users = 0;
$result = array();
//Comments
if (!empty($comment_array)) {
foreach ($comment_array as $item) {
if (!in_array($item['user'], $uniqueUsers)) {
array_push($uniqueUsers, $item['user']);
$result[$item['user']] = 0;
}
$votes ++;
$result[$item['user']] += $item['points'];
}
}
// Likes
if (!empty($like_array)) {
foreach ($like_array as $item) {
if (!in_array($item['user'], $uniqueUsers)) {
array_push($uniqueUsers, $item['user']);
$result[$item['user']] = 0;
}
$votes ++;
$result[$item['user']] += $item['points'];
}
}
// Posts
if (!empty($post_array)) {
foreach ($post_array as $item) {
if (!in_array($item['user'], $uniqueUsers)) {
array_push($uniqueUsers, $item['user']);
$result[$item['user']] = 0;
}
$votes ++;
$result[$item['user']] += $item['points'];
}
}
foreach ($result as $idUser=>$points) {
echo "\n";
echo "\n" . 'User: ' . $idUser;
echo "\n" . 'Points: ' . $points;
}
$results = array('users'=> count($uniqueUsers), 'votes'=>$votes, 'points'=> $points);
//print_r($results);
The solution using array_column, array_walk_recursive and array_values functions:
...
$comments = array_column($comment_array, 'points', 'user');
$likes = array_column($like_array, 'points', 'user');
$posts = array_column($post_array, 'points', 'user');
$list = [$comments, $likes, $posts];
$result = [];
array_walk_recursive($list, function($v, $k) use(&$result){
if (key_exists($k, $result)){
$result[$k]['points'] += $v;
} else {
$result[$k] = ['user' => $k, 'points' => $v];
}
});
$result = array_values($result);
print_r($result);
The output:
Array
(
[0] => Array
(
[user] => 5
[points] => 12
)
[1] => Array
(
[user] => 2
[points] => 2
)
[2] => Array
(
[user] => 3
[points] => 4
)
[3] => Array
(
[user] => 1
[points] => 13
)
[4] => Array
(
[user] => 4
[points] => 4
)
)
Do the following to get one array with summed points:
$collections = array(
'comments' => json_decode($comments,TRUE),
'likes' => json_decode($likes,TRUE);,
'posts' => json_decode($posts,TRUE),
);
$newArray = array();
foreach ($collections as $collection) {
foreach ($collection as $user) {
$newArray[$user->user] += $user->points;
}
}
There are two important points to make if you want to learn the "best" way to handle these types of operations.
Don't use iterated in_array() calls when isset() can be used instead. This is because isset() is much more efficient than in_array().
Use temporary keys to identify duplicate occurrences, then re-index your results when finished -- usually with array_values(), but this time I used array_multisort() to re-order the results AND re-index.
Code: (Demo)
$merged = array_merge(json_decode($comments, true), json_decode($likes, true), json_decode($posts, true));
$result = [];
foreach ($merged as $entry) {
if (!isset($result[$entry['user']])) {
$result[$entry['user']] = $entry;
} else {
$result[$entry['user']]['points'] += $entry['points'];
}
}
array_multisort(array_column($result, 'user'), $result);
// usort($result, function($a, $b) { return $a['user'] <=> $b['user']; });
// array_multisort() will outperform `usort()` in this case.
echo json_encode($result);
Output:
[{"user":"1","points":13},{"user":"2","points":2},{"user":"3","points":4},{"user":"4","points":4},{"user":"5","points":"12"}]
Decode each array and merge them together into a multi-dimensional array.
Iterate each subarray and determine if it is the first occurrence of the user. If so, retain the entire subarray. If not, only increase the points tally within that subarray.
When the loop is finished, sort by user ascending.
This is clean, direct, and readable.

Prepend key value to array - PHP

I have the below code in a for..loop is there a way I can add values to the beginning of the array?
$data = array();
$initial = strtotime('11:00:00');
for (; $initial < strtotime("23:00:59"); $initial = strtotime("+15 minutes", $initial)) {
if ($initial > strtotime("+45 minutes", time())) {
$row['value'] = date('Hi', $initial);
$row['label'] = date('H:i', $initial);
$data['data'][] = $row;
}
}
I want to add the below values to the top of the array. I have tried using array_unshift but I don't think it supports key-value pairs.
if(!isBetween('22:00', '09:59', date('H:i'))) {
$row['value'] = "asap";
$row['label'] = "ASAP";
}
My array output
{
"data": [
{
"value": "1145",
"label": "11:45"
}
]
}
I want to get this
{
"data": [
{
"value": "asap",
"label": "ASAP"
},{
"value": "1145",
"label": "11:45"
},
]
}
Un-shift should work if you pass the arguments correctly:
array_unshift($data["data"], $prepend);
Alternatively, you could use array_merge, like this:
$data["data"] = array_merge(array($prepend), $data["data"]);
With the following example data:
$data = [
"data" => [
[
"value" => "1145",
"label" => "11:45"
]
]
];
$prepend = [
"value" => "asap",
"label" => "ASAP"
];
$data["data"] = array_merge(array($prepend), $data["data"]);
print_r($data);
You would get this output (with both solutions):
Array (
[data] => Array (
[0] => Array (
[value] => asap
[label] => ASAP
)
[1] => Array (
[value] => 1145
[label] => 11:45
)
)
)
If you need to prepend something to the array without the keys being reindexed and/or need to prepend a key value pair, you can use this short function:
function array_unshift_assoc(&$arr, $key, $val) {
$arr = array_reverse($arr, true);
$arr[$key] = $val;
return array_reverse($arr, true);
}
Source: http://php.net/manual/en/function.array-unshift.php

How to get values from nested JSON data?

Here's my JSON code:
{
"query": {
"count": 2,
"created": "2013-04-03T09:47:03Z",
"lang": "en-US",
"results": {
"yctCategories": {
"yctCategory": {
"score": "0.504762",
"content": "Computing"
}
},
"entities": {
"entity": [
{
"score": "0.902",
"text": {
"end": "19",
"endchar": "19",
"start": "0",
"startchar": "0",
"content": "Computer programming"
},
"wiki_url": "http://en.wikipedia.com/wiki/Computer_programming"
},
{
"score": "0.575",
"text": {
"end": "51",
"endchar": "51",
"start": "41",
"startchar": "41",
"content": "programming"
}
}
]
}
}
}
}
and below is my PHP code
$json_o = json_decode($json,true);
echo "Json result:</br>";
echo $json; // json
echo "</br></br>";
echo "Value result:</br>";
$result = array();
//$entity = $json_o['query']['results']['entities']['entity'];
foreach ($json_o['query']['results']['entities']['entity'] as $theentity)
foreach ($theentity['text'] as $thetext){
$result[] = $thetext['content'];
}
print_r($result);
My expectation is to get the value of content in entity, which is "Computer programming" and "programming".
I already searching around, but still have found the solution yet.
The result of my PHP code is:
Array ( [0] => 1 [1] => 1 [2] => 0 [3] => 0 [4] => C [5] => 5 [6] => 5 [7] => 4 [8] => 4 [9] => p )
Use this loop
foreach ($json_o['query']['results']['entities']['entity'] as $theentity)
{
$result[] = $theentity['text']['content'];
}
http://codepad.viper-7.com/tFxh1w
Output Array ( [0] => Computer programming [1] => programming )
Change your foreach to:
$result = array();
foreach ($json_o['query']['results']['entities']['entity'] as $theentity) {
$result[] = $theentity['text']['content'];
}
print_r($result);
$theentity['text'] is an array of keys => value. You can just access key content instead of looping through all of the entries.
Another way you could do it (though it is a poor choice) is:
foreach($theentity['text'] as $key => $value) {
if( 'content' === $key ) {
$result[] = $value;
}
}
I provide this second example to demonstrate why the original code did not work.
Update
To access other properties like the yctCategories just do something similar
$categories = array();
foreach ($json_o['query']['results']['yctCategories'] as $yctCategory) {
$categories[] = $yctCategory['content'];
}
print_r($categories);
remove the second foreach and replace it with $result[] = $theentity['text']['content'];
using something like http://jsonlint.com/ might make it easier for you to see how the json is structured. alternatively just var_dump (or print_r) the output of your json_decode.
Use simple code:
$array = $json_o['query']['results']['entities']['entity'];
foreach($array as $v){
echo $v['text']['content'];
}

Categories