How to combine array with same values - php

Okay so not 100% sure how to even ask this correctly but I have an array that I'm trying to consolidate and group together based on each hour, and then data for each year underneath that time.
My current array looks like this:
[
{
"name": "7:00 AM",
"data": [
{
"x": "2019",
"y": 1
}
]
},
{
"name": "7:00 AM",
"data": [
{
"x": "2020",
"y": 221
}
]
}
]
So I'm looking to combine these into a single array based on the name value and then all of the data will be combined:
[
{
"name": "7:00 AM",
"data": [
{
"x": "2019",
"y": 1
},
{
"x": "2020",
"y": 221
}
]
}
]
EDIT: And just to add how I'm originally getting and formatting these values, I'm using Larvel and running the following query:
$shipments = Orders::whereNotNull('shipped_at')->groupBy(DB::raw('YEAR(created_at)'))->selectRaw('count(*) as count, HOUR(shipped_at) as hour')->selectRaw("DATE_FORMAT(created_at, '%Y') label")->orderBy('label')->orderBy('hour')->groupBy('hour')->get();
And that gives me the following data:
And then I'm building the original array like this:
$shipping_chart_year = [];
foreach ($shipments as $item) {
$hour = Carbon::parse($item['hour'] . ':00:00')->timezone('America/Chicago')->format('g:i A');
$shipping_chart_year[] = ['name' => $hour, 'data' => [['x' => $item['label'], 'y' => $item['count']]]];
}

This functions formats array as you expected to have.
function formatArray($array){
$response = [];
$keysIndexes = [];
foreach($array as $value) {
if(!array_key_exists($value['name'], $keysIndexes)) {
array_push($response, $value);
$keysIndexes[$value['name']] = sizeof($keysIndexes);
} else {
array_push($response[$keysIndexes[$value['name']]]['data'], $value['data'][0]);
}
}
return $response;
}

if you want to achieve this with the Laravel Collections (you can do so much with it!), here you go (based on your current array structure).
It is much more readable and way easier to achieve.
$output = collect(json_decode($data, true))
->groupBy('name')
->transform(function ($items, $name) {
// Merge nested arrays into one
$data = $items->map(function ($item) {
return $item['data'][0];
})->toArray();
return [
'name' => $name,
'data' => $data,
];
})
->values() // removes the key
->toJson(); // returns the collection to json

Related

PHP change a function from from loops to recursion

I have the following JSON object:
{
"id": 1,
"name": null,
"block": {
"type": "none",
"descends": [
{
"operation":"sum",
"descends":[
{
"label":2,
"value":false
}
]
},
{
"label": 1,
"value": 3,
},
{
"label": 2,
"value": 2
}
],
"label": 1,
"value": true
}
}
I want to collect all the label and value attributes and store them in an array, so I created the following function:
public function collectValues($arr){
$finalValues = [];
foreach($arr as $key => $element){
if($key=='block'){
foreach($element as $key2 => $block){
if($key2=='descends'){
foreach($block as $key3 => $node_block){
if($key3=='descends'){
foreach($node_block as $key4 => $anotherNode){
if($key4 == 'descends'){
foreach($anotherNode as $finalNode){
$finalValues [] = array('lable'=>$finalNode->label, 'value' =>$finalNode->value);
}
}
}
}
else{
$finalValues [] = array('lable' => $node_block->label, 'value' => $node_block->value);
}
}
}
}
$finalValues [] = array('lable'=> $element->label, 'value' => $element->value);
}
}
return $finalValues;
}
The function works and I get the following:
[
{
"lable": 2,
"value": false
},
{
"lable": 1,
"value": 3
},
{
"lable": 2,
"value": 2
},
{
"lable": 1,
"value": true
}
]
The problem is that the JSON object can contain more descends like:
{
"id": 1,
"name": null,
"block": {
"type": "none",
"descends": [
{
"operation":"sum",
"descends":[
{
"operation":"sum",
"descends":[
{
"label":2,
"value":false
}
],
"label":2,
"value":false
}
]
},
{
"operation":"sum",
"descends":[
{
"label":2,
"value":false
}
],
"label": 1,
"value": 3,
},
{
"label": 2,
"value": 2
}
],
"label": 1,
"value": true
}
}
This means I will have to add more foreach loops. A good way to handle such a situation is by using recursive. How can I transform the function above into a recursive one?
Your looped function does not make sense to change. Easier to rewrite from scratch
Here is my use case for recursion. Maybe there is an easier option, but I didn’t chase optimization
$array = json_decode($json, true); //in $json your JSON)
$result = []; // array for result
checkLabel($array, $result);
print_r($result);
function checkLabel(array $array, &$result){
//first check every element on nested array
foreach ($array as $key => $value){
if (is_array($value)) {
//if found call recursive function
checkLabel($value, $result);
}
}
//then check 'label' key.. its mean we have attribute
if (array_key_exists('label', $array)) {
//save it
$result[] = [
'label' => $array['label'],
'value' => $array['value']??'' //if have label but without value)
];
}
}

modify json data in php laravel

I've a sample json data
{
"cities": {
"total": 100,
"count":5000,
"cities_list" : [{
"name": "city1",
"count": 1000
},
{
"name": "city2",
"count": 2000
}
]
}
}
How can I append the cities_list array directly to cities which would look like
{
"cities": [{
"name": "city1",
"count": 1000
},
{
"name": "city2",
"count": 2000
}
]
}
Not sure, about all the stuff, but i assume your "json" or just associative array is in variable (for example foo)
Now you should set:
$foo["cities"] = $foo["citites"]["citites_list"];
Let's say that your JSON result is stored in a variable called $results
$results = json_decode($results,true); //convert json to array
$modifiedArray= [];
$modifiedArray= $results['cities']['cities_list']->map(function ($item, $key) {
return ['cities'][][
'name' => $item->name,
'count' => $item->count
];
});
This is more of a laravel approach since you also tagged laravel. Your modified array is an array type if you want to be a JSON again you have to encode it into a JSON.
You can use the Unset function
$data= json_decode($your_json);
$json_arr = json_decode($your_json, true);
unset($data->total);
unset($json_arr['total']);

How to convert a string inside an array to array and combine both together?

I have an array which look like this :
Result 1:
{
"error_code": 0,
"error_message": "",
"return_data": {
"items": [
{
"id": 462,
"users": "1,36,38"
},
{
"id": 462,
"users": "1,4"
},...... //same for 20 result
]
}
}
I want the users to convert to an array,and separate by the comma,so the whole result will look like this :
The result I want:
{
"error_code": 0,
"error_message": "",
"return_data": {
"items": [
{
"id": 462,
"users": [
{
"user_id": 1
},
{
"user_id": 36
},
{
"user_id": 38
}
],
}.. //other result
]
}
}
Here is what I try :
$res = "array the get the Result 1";
$items = //"I get the items array"
foreach ($items as $key => $item) {
$usersArray = array(); //create a new Array
//spilt the string to array separate with ","
$usersIdArray = explode(',', $items['users']);
//assign the "user_id" key to each value
foreach ($userIdArray as $key => $user) {
$usersArray['user_id'] = $user;
}
//assign the result back to $res
$res['return_data']['items']['users'] = $usersArray;
}
After I assign the array to $res with this line of code $res['return_data']['items']['users'] = $usersArray; ,my result become like below,I state the problem inside the code :
{
"error_code": 0,
"error_message": "",
"return_data": {
"items": {
"0":{ <-- // here suddenly appear a number for each result
"id": 462,
"users": "1,36,38" //here nothing change (I want the array appear here)
},
"1":{
"id": 462,
"users": "1,36,38"
},
"2":{
"id": 462,
"users": "1,36,38"
},
"users": { //the array appear here but not the position I want..and it only appears 1 time.
"user_id": "38"
}
}
}
}
So my question is,how can I convert a String in an array to an array,assign value to the key,and make it inside the array?
Somebody please help..Thanks
Like the comments above, you could have done it the first time so you wouldn't need another structure conversion, but anyway, your code is already there a bit, its just you need to create another nesting since you want another level:
So you need another level here:
"users": [
{
"user_id": 1
},
{
"user_id": 36
},
{
"user_id": 38
}
],
So in the code, just add []. This translates into:
foreach ($items as $key => $item) {
$usersArray['id'] = $item['id'];
$usersArray['users'] = array(); //create a new Array
$usersIdArray = explode(',', $item['users']);
foreach ($usersIdArray as $key => $user) {
$usersArray['users'][] = array('user_id' => $user); // push each batch of key pair "user_id" key and value "each exploded id"
// another level ^
}
$res['return_data']['items'][] = $usersArray;
}
Here's the fiddle to check it out.

Query to get time count from mongodb

I have my data in mongodb database as
{
"_id": ObjectId("5319acf0b06f6e98371ca505"),
"field1": "",
"date": "07-03-2014",
"os": "android",
"time": "11:26:40",
"userid": "xxxx"
}
I wanted to get count of all records having time from 00 to 23.
I have written my query as
$time_start = date('00');
$time_end = date('23');
$keys = array("time" => 1);
$initial = array("counttime" => array());
$reduce = "function(obj, prev) {
if (obj.time != null)
if (obj.time instanceof Array) prev.counttime += obj.time.length;
else prev.counttime++; }";
$condition = array(
'condition' => array(
"time" => array(
'$gt' => $time_start,
'$lte' => $time_end
)
)
);
$g = $collection->group($keys, $initial, $reduce , $condition);`
I have tried to get hour but thats not working for me.
I have used as
$condition = array(
'condition' => array(
"HOUR(time)" => array(
'$gt' => $time_start,'$lte' => $time_end)
)
);
Anyone who can help me out?
You can do this using .aggregate(), which you really should favor over .group() in any case, as it uses native code rather than JavaScript for it's results:
db.collection.aggregate([
// Match one date (tell you later)
{ "$match": { "date": "07-03-2014" } },
// Project the hour
{ "$project": {
"hour": { "$substr": [ "$time", 0, 2 ] }
}},
// Group on the hour
{ "$group": {
"_id": "$hour",
"count": { "$sum": 1 }
}}
])
Now this relies on that you have your "time" stored as a string. So you $project the "hour" part of that "time" and then $group on it, keeping a count of records found.
I restricted this to one "date" because as with "time" this is also a string. Depending on what you want to do you can possibly get unexpected results from this, so generally speaking, using "strings" for date representation is not a good idea.
If you just had a proper BSON date in a field called "timestamp" then you can do things like this, where you can even set ranges:
var start_date = new Date("2014-02-01");
var end_date = new Date("2014-03-01");
db.collection.aggregate([
// Match on the date range
{ "$match": { "timestamp": { "$gte": start_date, "$lt": end_date } },
// Project day and hour
{ "$project": {
"day": {
"year": { "$year": "$timestamp" },
"month": { "$month": "$timestamp" },
"day": { "$dayOfMonth": "$timestamp" },
"hour": { "$hour": "$timestamp" }
}
}},
// Group on the day
{ "$group": {
"_id": "$day",
"count": { "$sum": 1 }
}}
])
But with your present date format, ranges are going to be a problem. So best to convert where you can.

make order in json decode

[
{
"id": "123",
"name": "aaa"
},
{
"id": "567",
"name": "bbb"
},
{
"id": "469",
"name": "ccc"
},
{
"id": "577",
"name": "ddd"
},
{
"id": "388",
"name": "eee"
}
]
How to make a order when json decode?
$data = json_decode($json);
foreach ($data as $row) {
sort($row)?
}
I need all the decode data make an order by id.
Final data output: "name": "aaa", "name": "eee", "name": "ccc", "name": "bbb", "name": "ddd"
You could use usort().
$data = json_decode($json);
usort($data, function($a, $b) {
if ($a->id == $b->id) {
return 0;
}
return $a->id < $b->id ? -1 : 1;
});
Or, if you're using PHP < 5.3, you need to define the comparison function, since the support for anonymous functions was added in PHP 5.3.
function cmp($a, $b) {
if ($a->id == $b->id) {
return 0;
}
return $a->id < $b->id ? -1 : 1;
}
$data = json_decode($json);
usort($data, 'cmp');
This would sort the array. After that, if you want to create an array with only the name values, you could do that with a foreach.
$result = array();
foreach ($data as $entry) {
$result[] = array('name' => $entry->name);
}
The $result variable will now contain:
array(array('name' => 'aaa'),
array('name' => 'eee'),
array('name' => 'ccc'),
array('name' => 'bbb'),
array('name' => 'ddd'));
Then, to encode the result as JSON again, you can call json_encode().
echo json_encode($result);
This will output a string similar to:
[{"name": "aaa"},
{"name": "eee"},
{"name": "ccc"},
{"name": "bbb"},
{"name": "ddd"}]

Categories