Combine intersecting keys and values in 2 arrays - php

I'm running through all of the array functions on php.net and unable to figure this out.
Essentially I want to take these two arrays:
Array
(
[0] => stdClass Object
(
[month] => October
[year] => 2015
[credit] => 1000.00
)
[1] => stdClass Object
(
[month] => September
[year] => 2015
[credit] => 200.00
)
)
Array
(
[0] => stdClass Object
(
[month] => October
[year] => 2015
[debit] => 2000.00
)
[1] => stdClass Object
(
[month] => August
[year] => 2015
[debit] => 50.00
)
)
...and have the output look like this:
Array
(
[0] => stdClass Object
(
[month] => October
[year] => 2015
[credit] => 1000.00
[debit] => 2000.00
)
[1] => stdClass Object
(
[month] => September
[year] => 2015
[credit] => 200.00
[debit] => 0
)
[2] => stdClass Object
(
[month] => August
[year] => 2015
[credit] => 0
[debit] => 50.00
)
)
I'm looked to merge "month" and "year" and combine the other keys, using a default value if the key doesn't exist. Any guidance?

Assuming $debits and $credits are the arrays shown in your question, I would approach it like this:
First loop over the credits, inserting them into the new "combined" array and adding a default value for debit as you go.
foreach ($credits as $credit) {
$credit->debit = 0.00; // provide a default value for debit
$combined[$credit->year . $credit->month] = $credit;
}
Then loop over the debits. Since there is the possibilities that entries will already be there from credits, there needs to be a check for this. This part should update existing values inserted from credits, or insert new values if there is no existing value.
foreach ($debits as $debit) {
if (isset($combined[$debit->year . $debit->month])) {
// update the debit if the entry already exists
$combined[$debit->year . $debit->month]->debit = $debit->debit;
} else {
// otherwise create a new entry with a default value for credit
$debit->credit = 0.00;
$combined[$debit->year . $debit->month] = $debit;
}
}
// If you need the results to be numerically indexed, you can use array_values
$numerically_indexed = array_values($combined);

Related

PHP Combine multiple arrays of objects and change array structure

I have multiple separate arrays of objects that are imported (JSON-encoded) from MySQL that I need to merge and change structure. I basically need the combined [time] and [day] entries to be an array of [cycle] so I can loop over them. Currently after import/decoding the array of objects structure for each MySQL query looks like this:
(query 1)
stdClass Object
(
[day] => Array
(
[0] => stdClass Object
(
[day] => 1
[time] => 60
[name] => Running
[cycle] => 1
)
[1] => stdClass Object
(
[day] => 5
[time] => 30
[name] => Running
[cycle] => 1
)
)
[id] => 15359593
)
(query 2)
stdClass Object
(
[day] => Array
(
[0] => stdClass Object
(
[day] => 1
[time] => 55
[name] => Running
[cycle] => 2
)
[1] => stdClass Object
(
[day] => 5
[time] => 15
[name] => Running
[cycle] => 2
)
)
[id] => 36848901
)
The structure that need is:
stdClass Object
(
[day] => 1
[name] => Running
[cycle] => Array
(
[0] => stdClass Object
(
[time] => 60
[cycle] => 1
[day] => 1
)
[1] => stdClass Object
(
[time] => 55
[cycle] => 2
[day] => 1
)
)
[id] => 36848901
)
stdClass Object
(
[day] => 5
[name] => Running
[cycle] => Array
(
[0] => stdClass Object
(
[time] => 30
[cycle] => 1
[day] => 5
)
[1] => stdClass Object
(
[time] => 15
[cycle] => 2
[day] => 5
)
)
[id] => 1237465
)
I need the program to then iterate over the array using foreach [day] and then [cycle] to produce something like this:
name day cycle 1 cycle 2 cycle ..
Running 1 60 55 ..
Running 5 30 15 ..
..
It can only do it on a row by row basis. I don't have (much) control over this part of the process.
I have tried changing the structure by using foreach loops and array commands like this:
$newArray[] = array( "name" => $this->name, "day" => $this->day,
array("cycle" => $this->cycle, array("time" => $this->time, "cycle" =>
$this->cycle, "day" => $this->day)));
This gives me a structure that is almost right, per entry but not combined for all.
To combine them I've tried array_merge_recursive() and various variants but no luck.
So what I think I need is to merge the arrays of objects and then change the structure to have the values of each [time] and [day] to be nested inside the [cycle] so I can loop over them.
What is the best way to do this?
It is running on PHP 7.2.
More of my attempted code:
// get {data} part of JSON-encoded field for each mysql result
for ($x = 0; $x < $this->cycleCount; $x++) {
preg_match("/{.*}/",$this->tmpString[$x]['data'],$matches);
$this->data[$x] = json_decode($matches[0]);
foreach ($this->data[$x] as $day) {
$newArray[] = array( "name" => $day->name, "day" => $day->day,
array("cycle" => $day->cycle,
array("time" => $day->time,
"cycle" => $day->cycle,
"day" => $day->day)
)
);
}
$data = array();
$object = json_decode($querObject,true);
foreach($object as $day => $info)
{
foreach($info['cycle'] as $cycleInfo)
{
$data[$info['$id']]['name'] = $cycleInfo['name'];
$data[$info['$id']]['day'] = $cycleInfo['day'];
$data[$info['$id']]['id'] = $cycleInfo['id'];
$data[$info['$id']]['cycle'][] =array('time'=>$cycleInfo['time'],'cycle'=>$cycleInfo['cycle'],'day'=>=>$cycleInfo['day']);
}
}

Remove duplicate yyyy/mm from array

How I can remove duplicate entries based on Year and Month when my date format is YYYY-MM-DD? I tried removing days, but then I need to add the last day in the array, so my approach was wrong.
My array looks like this:
Array
(
[0] => Array
(
[id] => 9240399
[time] => 2018-01-01
[pages_indexed] => 942
)
[1] => Array
(
[id] => 9240322
[time] => 2018-01-02
[pages_indexed] => 940
)
[2] => Array
(
[id] => 9240344
[time] => 2018-01-03
[pages_indexed] => 947
)
[30] => Array
(
[id] => 9240344
[time] => 2018-01-31
[pages_indexed] => 947
)
[31] => Array
(
[id] => 9240344
[time] => 2018-02-01
[pages_indexed] => 1999
)
[32] => Array
(
[id] => 9240344
[time] => 2018-02-02
[pages_indexed] => 13339
)
Notice that I skipped some entries, so my dates are 2018-01-01, 2018-01-02, etc.
Array_unique would not work here since the day is different.
I tried this: ( $entries['time'] is like ex: 2018-01-01. )
$remove = DATE("Y-m",$entries['time']);
$entriesa = array_unique($remove);
$entries['time'] = $entriesa;
Well... you could loop through your results and index each key as the Year and Month, and then update this index with the row that fits the pattern, meaning you would only have the rows you expect (but you would only have the last reference of them).
Like this:
$expectedArray = [];
foreach ($arrayDuplicated as $item) {
$indexKey = substr($item['time'], 0, 7);
$expectedArray[$indexKey] = $item;
}

How to check if a specific key and value exist more than 3 times in php array

I have following 'challange';
I have array like this:
Array
(
[0] => stdClass Object
(
[id] => 94
[day] => Monday
[date] => 2018-07-09
[week_number] => 2
)
[1] => stdClass Object
(
[id] => 95
[day] => Tuesday
[date] => 2018-07-10
[week_number] => 2
)
[2] => stdClass Object
(
[id] => 83
[day] => Saturday
[date] => 2018-07-07
[week_number] => 1
)
[3] => stdClass Object
(
[id] => 82
[day] => Friday
[date] => 2018-07-06
[week_number] => 1
)
[4] => stdClass Object
(
[id] => 81
[day] => Thursday
[date] => 2018-07-05
[week_number] => 1
)
[5] => stdClass Object
(
[id] => 80
[day] => Wednesday
[date] => 2018-07-04
[week_number] => 1
)
)
I wanted to know how many times user have selected "week_number" 1,2 and so on, I don't want to allow user to select more than 3 events in a week.
I am using fullcalendar to display events.
How can I achieve that?
Thank you in advance
In PHP 7 you can extract the week_number properties and count the values:
$result = array_count_values(array_column($array, 'week_number'));
Will yield the week_number as the key and the count as the value:
array
(
[1] => 4
[2] => 2
)
Depending upon wheteher you want to check for multiples or just one, loop and check for > 3 or use in_array(3, $result).
You might use array_reduce to
$result = array_reduce($input, function($outpu, $item) {
if(!isset($output[$item->week_number])) {
$output[$item->week_number] = 0;
}
return $output[$item->week_number]++;
});
var_dump($result);
Where $input is You array of objects
If you only need to check if there are more than x events, and you don't need to count all events, better use something like this:
function hasTooManySelections($items, $maxSelections = 3)
{
$counts = [];
foreach ($items as $item) {
$counts[$item->week_number] = isset($counts[$item->week_number]) ? $counts[$item->week_number] + 1 : 1;
if ($counts[$item->week_number] > $maxSelections) {
return true;
}
}
return false;
}
var_dump(hasTooManySelections($items));
Demo: https://3v4l.org/XbiH0
You can sort your array in respect of group by week number and then count length of all perticular group

Search array of dates does not return result

Hello I am trying to search for an hour based on the current date with the following function:
$key = array_search($todayday, array_column($days, 'date', 'hours'));
Where $todayday is equal to today day which comes from the sever day date.
the Array $days is:
Array
(
[0] => Array
(
[date] => 01
[hours] => 0
)
[1] => Array
(
[date] => 02
[hours] => 8
)
[2] => Array
(
[date] => 03
[hours] => 16
)
[3] => Array
(
[date] => 04
[hours] => 24
)
[4] => Array
(
[date] => 05
[hours] => 32
)
[5] => Array
(
[date] => 06
[hours] => 40
)
[6] => Array
(
[date] => 07
[hours] => 40
)
... etc....
while $todaydate is equal to 1,2,3,4,5 it works. but for 6 and 7 does not return anything. Any help is welcome to resolve this issue. Thanks
I suspect that since date = 6 and 7 have the same value of hours this is why it does not return anything but the question is how to return it actually.
Your supposition is correct, you can not have duplicate keys. Use the key from the search and then access hours:
$key = array_search($todayday, array_column($days, 'date'));
$hours = $days[$key]['hours'];
Or shorter:
$hours = $days[array_search($todayday, array_column($days, 'date'))]['hours'];
In the case where the indexes are not 0 based and sequential, use array_values() to re-index:
$days = array_values($days);
$key = array_search($todayday, array_column($days, 'date'));
$hours = $days[$key]['hours'];

How to Group PHP Array Based On Year with Nested Array

My Current PHP Array Outputs like this:
Array
(
[0] => Array
(
[year] => 2015
[month] => November
)
[1] => Array
(
[year] => 2015
[month] => October
)
[2] => Array
(
[year] => 2015
[month] => September
)
[3] => Array
(
[year] => 2015
[month] => August
)
[4] => Array
(
[year] => 2015
[month] => July
)
[5] => Array
(
[year] => 2015
[month] => June
)
[6] => Array
(
[year] => 2015
[month] => May
)
[7] => Array
(
[year] => 2015
[month] => April
)
[8] => Array
(
[year] => 2015
[month] => March
)
[9] => Array
(
[year] => 2015
[month] => February
)
[10] => Array
(
[year] => 2015
[month] => January
)
[11] => Array
(
[year] => 2014
[month] => December
)
[12] => Array
(
[year] => 2014
[month] => November
)
[13] => Array
(
[year] => 2014
[month] => October
)
[14] => Array
(
[year] => 2014
[month] => September
)
[15] => Array
(
[year] => 2014
[month] => August
)
[16] => Array
(
[year] => 2014
[month] => July
)
)
I want to sort the above Array and group them based on the Year. The Array I want to convert the above is to get like this:
Array (
[0] => Array
(
[yearGroup] => “2015”
[dates] => Array
(
[0] => Array
(
[year] => 2015
[month] => November
)
[1] => Array
(
[year] => 2015
[month] => October
)
…etc..etc…
)
)
[1] => Array
(
[yearGroup] => 2014
[dates] => Array
(
[0] => Array
(
[year] => 2014
[month] => December
)
[1] => Array
(
[year] => 2014
[month] => November
)
…etc..etc…
)
)
)
This is the code I have tried so far:
$calendar = // ..... The Array Above .....;
$sidebarCalendar = array();
$currentYear = '';
$i = 0;
foreach ($calendar as $date) {
if ($currentYear != $date['year']) {
$currentYear = $date['year'];
$i++;
$tempYearDates = array();
$j = 0;
$tempYearDates[$j] = array(
'year' => $date['year'],
'month' => $date['month']
);
$j++;
// Add to Array
$sidebarCalendar[$i] = array (
'yearGroup' => $date['year'],
'dates' => $tempYearDates
);
}
else {
$tempYearDates = array(
'year' => $date['year'],
'month' => $date['month']
);
// Locate the Array Tree
$currentParent = $sidebarCalendar[$i];
$currentArray = $currentParent['dates'];
$currentArray[$j] = $tempYearDates;
$j++;
}
}
But the above outputs incomplete array like this:
Array
(
[1] => Array
(
[yearGroup] => 2015
[dates] => Array
(
[0] => Array
(
[year] => 2015
[month] => November
)
)
)
[2] => Array
(
[yearGroup] => 2014
[dates] => Array
(
[0] => Array
(
[year] => 2014
[month] => December
)
)
)
)
Can someone point out what I have got wrong here please? If there is a better way to do the same instead of the above method, please do guide me there please…
You could use some of the builtin PHP's array functions to solve this issue. First thing you want to do is get all the unique years in that array, so you could do:
$years = array_unique(array_map(function($item) { return $item['year']; }, $calendar));
Here, I've used array_map to get an array containing only the year property for each item, and fed it to the array_unique function to get only unique values.
Next thing you could do is iterate through all the years, and populate another array, something like this:
$grouped = [];
foreach($years as $year) {
$grouped[$year] = array_filter($calendar, function($item) use ($year) { return $item['year'] === $year; });
}
This way you'll get a key for each year in the grouped variable, and each key will contain a subarray composed only of the elements of calendar satisfying the array_filter condition.
I'm sure there are better / more optimized ways of doing this (maybe using array_walk or array_reduce?) and I encourage you to find those! Still, remember that there are many array functions builtin in PHP, read their documentation and learn when to use them, they'll be of great help!
Edit: I realize that the output of my solution is not exactly what you're expecting, but it's very easily adaptable. I myself prefer using keyed arrays (maps?) whenever possible in place of regular arrays with properties, but to each their own!
$grouped = [];
foreach($years as $year) {
$grouped[] = [
'yearGroup' => $year,
'dates' => array_filter($calendar, function($item) use ($year) { return $item['year'] === $year; })
];
}
Edit 2: Sometimes I forget how to PHP.

Categories