Remove multidimensional array with empty sub arrays using PHP - php

I have this array as follows. Every student has 7 arrays starting from Monday to Sunday and inner array of each has events for day
$array = [
'Alex' => [
[
['event' => 'eventName1'],['event' => 'eventName2']
],
[
['event' => 'eventName3'],['event' => 'eventName4']
],
[
['event' => 'eventName5'],['event' => 'eventName6']
],
[
['event' => 'eventName7'],['event' => 'eventName8']
],
[],
[],
[]
],
'christoper'=>[
[],[],[],[],[],[],[]
]
];
The output array should be
[
'Alex' => [
[
['event' => 'eventName1'],['event' => 'eventName2']
],
[
['event' => 'eventName3'],['event' => 'eventName4']
],
[
['event' => 'eventName5'],['event' => 'eventName6']
],
[
['event' => 'eventName7'],['event' => 'eventName8']
],
[],
[],
[]
]
];
I have tried this
$array = array_filter(array_map('array_filter', $array));
but the result is vain. Can anyone help me in getting desired output. I want to filter out students with no events

You can do this:
<?php
$output = array_filter($array, function (array $studentDays) {
foreach ($studentDays as $day) {
// if there is a *non-empty* day, we return early and keep the whole record
if (! empty($day)) {
return true;
}
}
// only empty days, so discard the record
return false;
});
https://3v4l.org/AkshS

Loop over array and apply array_filter
$array = [
'Alex' => [
[
['event' => 'eventName1'],['event' => 'eventName2']
],
[
['event' => 'eventName3'],['event' => 'eventName4']
],
[
['event' => 'eventName5'],['event' => 'eventName6']
],
[
['event' => 'eventName7'],['event' => 'eventName8']
],
[],
[],
[]
],
'christoper'=>[
[],[],[],[],[],[],[]
]
];
foreach( $array as $key => $value ){
$array[$key] = array_filter($value);
}
print_r( $array );

A recursive call to array_filter will do the job; in the outer call we check the size of the returned array to decide whether to keep that element or not (it will be 0 if the array consisted solely of empty arrays, as it does for 'christopher'):
$array = array_filter($array, function ($v) { return count(array_filter($v)); });
Demo on 3v4l.org

Related

Multidimensional array using objects

Is it possible to stop the loop from overwriting the previous value?
<?php
foreach (array('email1', 'email2') as $line) {
$x = [
$line => [
"Reports" => [
(object) [
"ReportType" => "1",
"SummaryFrequency" => [
(object) [
"FrequencyType" => "8011",
"SecondsPast" => "32400",
],
],
"Filter" => (object) [
"ClauseType" => "or",
"RuleField" => "",
"RuleOperator" => "",
"RuleValue" => "",
"ClauseChildren" => [
(object) [
"ClauseType" => "",
"RuleField" => "BackupJobDetail.TimeSinceStarted",
"RuleOperator" => "int_lte",
"RuleValue" => "86400",
],
],
],
],
],
],
];
}
print_r($x);
https://phpize.online/?phpses=e658de0de3dc1ed5a4d8d27ecebf567a&sqlses=null&php_version=php8&sql_version=mysql57
At the moment you overwrite $x each time, if you want to make it an array with $line as each index, create an empty array and then add the new items in with new index...
$x = [];
foreach (array('email1', 'email2') as $line) {
$x[$line] = [
"Reports" => [
(object) [

How to keep nested arrays on Laravel collection merge

I'm going crazy with that.
Given I have 2 arrays like
$array1 = [
"data_to_merge" => ["2020-03-11 16:00:00", "2020-03-24 14:00:00"],
"data_to_merge_past_year" => ["2019-03-11 16:00:00"],
];
$array2 = [
"data_to_merge" => [],
"data_to_merge_past_year" => ["2018-03-11 14:00:00"],
];
My goal is to have result like
all: [
"data_to_merge" => [
"2020-03-11 16:00:00",
"2020-03-24 14:00:00"
],
"data_to_merge_past_year" => [
"2018-03-11 14:00:00",
"2018-03-11 16:00:00",
],
],
I tried simple with
$result = collect($array1)->merge(collect($array2));
But with that approach it will remove the values from data_to_merge from my first array. Is there any Laravel way to get that result? It can be more than 2 arrays, just to demonstrate.
Here is my full example, it's basically the same
$array1 = [
"host" => "blablubb",
"data_to_merge" => [
"2020-03-11 16:00:00",
"2020-03-24 14:00:00"
],
"data_to_merge_past_year" => [
"2019-03-11 16:00:00"
],
];
$array2 = [
"host" => "blablubb",
"data_to_merge" => [],
"data_to_merge_past_year" => [
"2018-03-11 16:00:00"
],
];
$array3 = [
"host" => "blablubb",
"data_to_merge" => [],
"data_to_merge_past_year" => [],
];
$array4 = [
"host" => "blablubb",
"data_to_merge" => [
"2020-03-04 14:00:00",
"2020-03-04 17:00:00"
],
"data_to_merge_past_year" => [],
];
$all = collect([$array1, $array2, $array3, $array4]);
$all
->groupBy('host')
->map(function ($item) {
if (count($item) > 1) {
$result = collect([]);
foreach ($item as $subItem) {
$result = $result->merge($subItem);
}
return $result;
}
return $item->first();
})
->values()
->toArray();
Thanks guys!
You can use mergeRecursive for this:
$array1 = [
"data_to_merge" => ["2020-03-11 16:00:00", "2020-03-24 14:00:00"],
"data_to_merge_past_year" => ["2019-03-11 16:00:00"],
];
$array2 = [
"data_to_merge" => [],
"data_to_merge_past_year" => ["2018-03-11 14:00:00"],
];
$result = collect($array1)->mergeRecursive(collect($array2));
Result:
Illuminate\Support\Collection {#1278 ▼
#items: array:2 [▼
"data_to_merge" => array:2 [▼
0 => "2020-03-11 16:00:00"
1 => "2020-03-24 14:00:00"
]
"data_to_merge_past_year" => array:2 [▼
0 => "2019-03-11 16:00:00"
1 => "2018-03-11 14:00:00"
]
]
}
From the docs:
The mergeRecursive method merges the given array or collection
recursively with the original collection. If a string key in the given
items matches a string key in the original collection, then the values
for these keys are merged together into an array, and this is done
recursively:
$collection = collect(['product_id' => 1, 'price' => 100]);
$merged = $collection->mergeRecursive(['product_id' => 2, 'price' => 200, 'discount' => false]);
$merged->all();
// ['product_id' => [1, 2], 'price' => [100, 200], 'discount' => false]

How to fetch data from associative array in blade?

I am trying to fetch keys of array separately and values separately.
actual output:
[
"IT" => [
"Programming" => [
0 => "Python" 1 => "Java"
],
"Networking" => [
0 => "CCNA"
]
],
"Business" => [
"Power BI" => [
0 => "Power BI foundation"
]
]
]
desired output:
[
"IT",
"Business"
]
[
"Programming",
"Networking"
]
Does this script what you need?
$arr = [
"IT" => [
"Programming" => [
0 => "Python",
1 => "Java"
],
"Networking" => [
0 => "CCNA"
]
],
"Business" => [
"Power BI" => [
0 => "Power BI foundation"
]
]
];
$categories = [];
$subcategories = [];
foreach($arr as $key => $value) {
array_push($categories, $key);
array_push($subcategories, array_keys($value));
}
$categories equals:
["IT","Business"]
$subcategories equals :
[
["Programming","Networking"],
["Power BI"]
]
after execution.
Nevertheless, I would recommend to restructure your fetch script that has the array contained in $arr as output to avoid unnecessary loops.

Custom sorting multidimensional with n items by highest value

I am currently able to sort a multidimensional array using a custom sorting method. Each array lineupSet has an n amount of items. The function sort_points will sort each lineupSet from highest to lowest totalPoints and then it will give me the lineupSet with the the highest total totalPoints. I am currently changing the approach, I still want to sort through each lineupSet first and order highest to lowest. Then I would like to get the highest totalPoints of each lineupSet based on a given count. What would be the best way to approach this?
Test Array:
$testArray = [[
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 214.61,
],
"name" => "arr0-test0",
], [
"formula" => [
"totalPoints" => 201.17,
],
"name" => "arr0-test1",
]], [
"formula" => [
"totalPoints" => 5.01,
],
"name" => "arr0-test2",
]],
], [
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 214.76,
],
"name" => "arr1-test0",
], [
"formula" => [
"totalPoints" => 220.66,
],
"name" => "arr1-test1",
]],
],
], [
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 205.71,
],
"name" => "arr2-test0",
], [
"formula" => [
"totalPoints" => 204.43,
],
"name" => "arr2-test1",
]],
],
], [
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 205.48,
],
"name" => "arr3-test0",
], [
"formula" => [
"totalPoints" => 203.51,
],
"name" => "arr3-test1",
]],
],
]];
Sorting Function
function sum_points($v) {
$totalPoints = 0;
foreach ($v['lineupSet'] as $lset) {
if (isset($lset['formula'])) {
$totalPoints += $lset['formula']['totalPoints'];
}
else {
foreach ($lset as $l) {
$totalPoints += $l['formula']['totalPoints'];
}
}
}
return $totalPoints;
}
function sort_points($a, $b) {
return sum_points($b) - sum_points($a);
}
usort($testArray, 'sort_points');
print_r($testArray[0]);
For example I want to get the top two highest 'totalPoints'. The desired outcome:
Array (
[lineupSet] => Array
(
[0] => Array
(
[0] => Array
(
[formula] => Array
(
[totalPoints] => 220.66
)
[name] => arr1-test1
)
[1] => Array
(
[formula] => Array
(
[totalPoints] => 214.76
)
[name] => arr0-test0
)
)
)
)
I want to do the same for the top n highest totalPoints. Keeping in mind that it will have to take at times n items from each lineupSet that are the highest totalPoints.
I think it's better to use an object then you can keep max while you are sorting data (also you can use a constructor to sort the array).
Class SortHelper{
public $max = 0;
private function checkMax($totalPoints){
if($totalPoints > $this->max)
$this->max = $totalPoints;
}
private function sum_points($v) {
$totalPoints = 0;
foreach ($v['lineupSet'] as $lset) {
if (isset($lset['formula'])) {
$totalPoints += $lset['formula']['totalPoints'];
$this->checkMax($lset['formula']['totalPoints']);
}
else {
foreach ($lset as $l) {
$totalPoints += $l['formula']['totalPoints'];
$this->checkMax($l['formula']['totalPoints']);
}
}
}
return $totalPoints;
}
private function sort_points($a, $b) {
return $this->sum_points($b) - $this->sum_points($a);
}
public function sort($array){
usort( $array, [$this, 'sort_points']);
return $array;
}
}
then you would have:
$sortHelper = new SortHelper();
$sorted_array = $sortHelper->sort($testArray);
var_dump($sorted_array[0]);
var_dump($sortHelper->max);
Check this out,
$n = 2; // number of elements
$testArray = [[
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 214.61,
],
"name" => "arr0-test0",
], [
"formula" => [
"totalPoints" => 201.17,
],
"name" => "arr0-test1",
]], [
"formula" => [
"totalPoints" => 5.01,
],
"name" => "arr0-test2",
]
],
], [
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 214.76,
],
"name" => "arr1-test0",
], [
"formula" => [
"totalPoints" => 220.66,
],
"name" => "arr1-test1",
]],
],
], [
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 205.71,
],
"name" => "arr2-test0",
], [
"formula" => [
"totalPoints" => 204.43,
],
"name" => "arr2-test1",
]],
],
], [
"lineupSet" => [
[[
"formula" => [
"totalPoints" => 205.48,
],
"name" => "arr3-test0",
], [
"formula" => [
"totalPoints" => 203.51,
],
"name" => "arr3-test1",
]],
],
]];
function sort_points($a, $b)
{
return ($a['formula']['totalPoints'] > $b['formula']['totalPoints']) ? -1 : 1;
}
$result = [];
$reference = &$result['lineupSet'][0]; // store reference in $reference
foreach ($testArray as $tA) {
foreach ($tA['lineupSet'] as $t) {
foreach ($t as $child) {
$reference[] = $child;
}
}
}
usort($reference, 'sort_points');
$reference = array_slice($reference, 0, $n);
var_dump($result); // desired output
Please try this 2 functions, the steps as follows:
sort_points(); Sort it with arsort PHP function and return it to new simplified array.
transform_arrays($sortedArray, $testArray); $testArray will be changed the value by the sortedArray.
copy all the codes into single file of .php and run it.
*i assume that we don't care about the complexity, also in real life (in this case my life) there is nothing such the case that you need to sort in multidimensional array, because array is just the storage to keep the data can be read by human.
<?php
$testArray =
[
['lineupSet' => [[['formula' => ['totalPoints' => 214.61],'name' => 'arr0-test0'],['formula' => ['totalPoints' => 220.66],'name' => 'arr1-test1']]]],
['lineupSet' => [[['formula' => ['totalPoints' => 205.71],'name' => 'arr2-test0'],['formula' => ['totalPoints' => 204.43],'name' => 'arr2-test1']]]],
['lineupSet' => [[['formula' => ['totalPoints' => 205.48],'name' => 'arr3-test0'],['formula' => ['totalPoints' => 203.51],'name' => 'arr3-test1']]]]
];
// sort into another array
function sort_points($testArray = []){
$response = $result = [];
$i = 0;
foreach($testArray as $array2){
foreach($array2['lineupSet'][0] as $item){
$result[$item['name']] = $item['formula']['totalPoints'];
$i++;
}
}
arsort($result);
$i = 0;
foreach($result as $key => $val){
$response[$i]['name'] = $key;
$response[$i]['totalPoints'] = $val;
$i++;
}
return $response;
}
// this won't work if the $testArray format structure is changed
function transform_arrays($items, $testArray){
$l = 0;
for($i=0;$i<count($testArray);$i++){
for($j=0;$j<count($testArray[$i]);$j++){
for($k=0;$k<count($testArray[$i]['lineupSet'][$j]);$k++){
$testArray[$i]['lineupSet'][$j][$k]['formula']['totalPoints'] = $items[$l]['totalPoints'];
$testArray[$i]['lineupSet'][$j][$k]['name'] = $items[$l]['name'];
// print_r($testArray[$i]['lineupSet'][$j][$k]['formula']['totalPoints']);
// print_r($testArray[$i]['lineupSet'][$j][$k]);
$l++;
}
}
}
return $testArray;
}
echo '<pre>';
$sortedArray = sort_points($testArray);
$response = transform_arrays($sortedArray, $testArray);
print_r($response);
echo '</pre>';

How to push items into array in php

I am using Laravel with ES and trying to build a dynamic query.
But the following doesnt work:
$query[] = ['term' => ['city' => 1]];
$query[] = ['term' => ['state' => 2]];
$query[] = ['range' => ['price' => ['lte' => 2]]];
$asd = ['filtered' => [
'query' => [
'match' => ['title' => Input::get('query')]
],
'filter'=> [
'bool' => [
'must' => [
['term' => [ 'is_active' => 1] ],
[ 'range' => [
'end_date' => [
'from' => 'now'
]
]
],
$query
]
]
],
],];
echo json_encode($asd);
This will append $query[] wrong into $asd, like:
{"term":{"is_active":1}},
{"range":{"end_date":{"from":"now"}}},
[
{"term":{"city":1}},
{"term":{"state":2}},
{"range":{"price":{"lte":2}}}
]
How I would like to append it is:
{"term":{"is_active":1}},
{"range":{"end_date":{"from":"now"}}},
{"term":{"city":1}},
{"term":{"state":2}},
{"range":{"price":{"lte":2}}}
without the [] around it.
Solved:
$asd = ['filtered' => [
'query' => [
'match' => ['title' => Input::get('query')]
],
'filter'=> [
'bool' => [
'must' =>
$query
]
],
],];
A valid json string always consist of a single object or an array of objects.
The string you are asking for is not legal json, it would not be possible to parse.
Json with a single object looks like this:
{ // Object start.
"property": "value" // Where value could be a object or array or whatever.
} // Object end.
And if an array:
[ // Array start.
"Array value" // which could be an object or another array or whatever.
] // Array end.
When you convert your PHP array containing associative arrays, it will be converted into a string containing a array of objects.
You could always remove the [] from the string if you wish it to look like you described, but it will not be valid json.
Edit:
An elastic query looks basically like this:
{
"query": {
"term": { data ... }
}
}
I'm guessing that what you want/need to do is to create the php array like this:
$query = [
'query' => [
'term' => [
'state' => 2
'city' => 1
],
'range' => [
'price' => [
'lte' => 2
]
]
]
]
Which would result in a JSON string that looks like this:
{
"query":
{
"term":
{
"state": 2,
"city": 1
},
"range":
{
"lte": 2
}
}
}

Categories