I am populating an array of dates from two sources: an array of dates and a range of dates between two dates.
$dateann = ['2024-08-16', '2024-08-11', '2024-08-16', '2024-09-16'];
$period = CarbonPeriod::between('2024-08-01', '2024-08-31');
foreach ($period as $date) {
$days[] = $date->format('Y-m-d');
}
$array_dates = array_merge($dateann, $days);
This can result in duplicate dates in the merged array. I would like to replace any recurring dates with an empty string.
Current output:
array: [
0 => "2024-08-16"
1 => "2024-08-11"
2 => "2024-08-16"
3 => "2024-09-05"
4 => "2024-08-01"
5 => "2024-08-02"
6 => "2024-08-03"
7 => "2024-08-04"
8 => "2024-08-05"
9 => "2024-08-06"
10 => "2024-08-07"
11 => "2024-08-08"
12 => "2024-08-09"
13 => "2024-08-10"
14 => "2024-08-11"
15 => "2024-08-12"
16 => "2024-08-13"
17 => "2024-08-14"
18 => "2024-08-15"
19 => "2024-08-16"
20 => "2024-08-17"
21 => "2024-08-18"
22 => "2024-08-19"
23 => "2024-08-20"
24 => "2024-08-21"
]
Desired output:
array: [
0 => "2024-08-16"
1 => "2024-08-11"
2 => ""
3 => "2024-09-05"
4 => "2024-08-01"
5 => "2024-08-02"
6 => "2024-08-03"
7 => "2024-08-04"
8 => "2024-08-05"
9 => "2024-08-06"
10 => "2024-08-07"
11 => "2024-08-08"
12 => "2024-08-09"
13 => "2024-08-10"
14 => ""
15 => "2024-08-12"
16 => "2024-08-13"
17 => "2024-08-14"
18 => "2024-08-15"
19 => ""
20 => "2024-08-17"
21 => "2024-08-18"
22 => "2024-08-19"
23 => "2024-08-20"
24 => "2024-08-21"
]
10
Check if the current index is the same as the first index of the value. If not, replace the value with an empty string.
foreach ($array_dates as $index => $value) {
if (array_search($value, $array_dates) != $index) {
$array_dates[$index] = '';
}
}
8
As a performance comparison, making value-based searches using array_search()
calls will be less efficient than making key-based searches. Here is a demonstration of how to skip the merge step and use null coalescing techniques on a lookup array that only grows in size as unique dates are encountered.
Code: (PHPize Demo)
$dateann = ['2024-08-16', '2024-08-11', '2024-08-16', '2024-09-16'];
foreach ($dateann as &$date) {
$date = $lookup[$date] ?? $date; // if not in the lookup, it's new
$lookup[$date] ??= ''; // flag the date in the lookup to only return an empty string
}
$period = CarbonPeriod::between('2024-08-01', '2024-08-31');
foreach ($period as $obj) {
$ymd = $obj->format('Y-m-d');
$dateann[] = $lookup[$ymd] ?? $ymd; // if not in the lookup, it's new
$lookup[$ymd] ??= ''; // flag the date in the lookup to only return an empty string
}
var_export($dateann);
1
I would recommend using a filter function. Something like the following would work for this use case:
function filterDates(array $dates): array
{
/** @var string[] The result array */
$result = [];
/** @var bool[] a lookup map for checking existence */
$lookup = [];
// loop through the array shifting each element off the front until empty
while ($date = array_shift($dates)) {
// check if already exists
if (isset($lookup[$date])) {
// set to empty string
$result[] = '';
continue;
}
// set lookup entry
$lookup[$date] = true;
// set date value
$result[] = $date;
}
return $result;
}
The above function, simply works its way through the array while keeping track of dates already set, then setting the duplicates to an empty string.
You can then pass in the merged array and it will set each repeating entry to an empty string.
$array_dates = filterDates(array_merge($dateann, $days));
Jarryd is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.