Return 日期间隔数组列表的重叠量
Return the amount of overlapping from arraylist of date intervals
我有以下名为 $all_data.
的数组
Array
(
[Chevenez] => Array
(
[41.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 03:53:37.49459
[1] => 2022-01-19 04:53:37.49459
)
[1] => Array
(
[0] => 2022-01-09 03:53:37.49459
[1] => 2022-01-09 04:53:37.49459
)
)
[41.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:23:37.49459
[1] => 2022-01-19 05:23:37.49459
)
[1] => Array
(
[0] => 2022-01-09 04:23:37.49459
[1] => 2022-01-09 05:23:37.49459
)
)
[42.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:03:37.49459
[1] => 2022-01-19 04:33:37.49459
)
[1] => Array
(
[0] => 2022-01-09 04:03:37.49459
[1] => 2022-01-09 04:33:37.49459
)
)
[42.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:13:37.49459
[1] => 2022-01-19 05:13:37.49459
)
[1] => Array
(
[0] => 2022-01-09 04:13:37.49459
[1] => 2022-01-09 05:13:37.49459
)
)
)
[Barcelona] => Array
(
[5.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 03:53:37.49459
[1] => 2022-01-19 04:53:37.49459
)
)
[5.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:23:37.49459
[1] => 2022-01-19 05:23:37.49459
)
)
[16.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:03:37.49459
[1] => 2022-01-19 04:33:37.49459
)
)
[16.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:13:37.49459
[1] => 2022-01-19 05:13:37.49459
)
)
)
)
从上面的数组中,我试图获得 Chevenez 和 Barcelona 的重叠时间间隔。假设对于 Chevenez,如果所有键 41.NEwan0、41.NEwan1、42.NEwan0 和 42.NEwan1 都重叠,则只考虑否则不重叠。
我已经尝试了 中提出的想法。
// Placeholder array to contain the periods when everyone is available.
$periods = [];
foreach($all_data as $key => $data){
// Loop until one of the people has no periods left.
while (count($data) && count(array_filter($data)) == count($data)) {
// Select every person's earliest date, then choose the latest of these
// dates.
$start = array_reduce($data, function($carry, $ranges) {
$start = array_reduce($ranges, function($carry, $range) {
// This person's earliest start date.
return !$carry ? $range[0] : min($range[0], $carry);
});
// The latest of all the start dates.
return !$carry ? $start : max($start, $carry);
});
// Select each person's range which contains this date.
$matching_ranges = array_filter(array_map(function($ranges) use($start) {
return current(array_filter($ranges, function($range) use($start) {
// The range starts before and ends after the start date.
return $range[0] <= $start && $range[1] >= $start;
}));
}, $data));
// Find the earliest of the ranges' end dates, and this completes our
// first period that everyone can attend.
$end = array_reduce($matching_ranges, function($carry, $range) {
return !$carry ? $range[1] : min($range[1], $carry);
});
// Add it to our list of periods.
$periods[$key][] = [$start, $end];
// Remove any availability periods which finish before the end of this
// new period.
array_walk($data, function(&$ranges) use ($end) {
$ranges = array_filter($ranges, function($range) use($end) {
return $range[1] > $end;
});
});
}
}
// Output the answer in the specified format.
foreach ($periods as $key => $period) {
foreach ($period as $period1) {
echo "$key : $period1[0] -> $period1[1]\n";
}
}
但它给了我下面的输出。
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Chevenez : 2022-01-19 04:03:37.49459 -> 2022-01-19 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
但我想要的输出是。
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Chevenez : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
它给了我 Chevenez : 2022-01-19 04:03:37.49459 -> 2022-01-19 04:33:37.49459 在第二行但是应该是 Chevenez : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
@amirreza-noori 我在跟随 arrry 时遇到错误。
$all_data = [
'Chevenez' => [
'41.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459'],
['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'41.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459'],
['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'42.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459'],
['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'42.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459'],
['2022-01-09 04:13:37.49459', '2022-01-09 05:13:37.49459']],
'43.NEwan0' => [['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'43.NEwan1' => [['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'44.NEwan0' => [['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'44.NEwan1' => [['2022-01-09 04:28:37.49459', '2022-01-09 05:13:37.49459']],
],
'Barcelona' => [
'5.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459']],
'5.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459']],
'16.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459']],
'16.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459']]
]
];
所需的输出是。
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
我发现了你对待日期的方式。因此无需将它们转换为浮点数。所以问题是关于算法的。以下代码可能是一个解决方案。
$all_data = [
'Chevenez' => [
'41.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459'],
['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'41.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459'],
['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'42.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459'],
['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'42.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459'],
['2022-01-09 04:13:37.49459', '2022-01-09 05:13:37.49459']],
'43.NEwan0' => [['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'43.NEwan1' => [['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'44.NEwan0' => [['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'44.NEwan1' => [['2022-01-09 04:28:37.49459', '2022-01-09 05:13:37.49459']],
],
'Barcelona' => [
'5.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459']],
'5.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459']],
'16.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459']],
'16.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459']]
]
];
$periods = [];
foreach($all_data as $place => $parts) {
// select first times of each place
$part1_times = $parts[array_key_first($parts)];
$periods[$place] = [];
// walk on times parts
foreach($part1_times as $t => $part1_time_range) {
$range_low = $part1_time_range[0];
$range_up = $part1_time_range[1];
// detect common range
foreach($parts as $part_times) {
if(!isset($part_times[$t])) break;
$rlow = $part_times[$t][0];
$rup = $part_times[$t][1];
if($rlow > $range_low) $range_low = $rlow;
if($rup < $range_up) $range_up = $rup;
}
if($range_low < $range_up) $periods[$place][] = [$range_low, $range_up];
}
// sort times in each place from small to big
usort($periods[$place], function($a, $b) {
return $a[0] > $b[0] ? 1 : -1;
});
}
// Output the answer in the specified format.
foreach ($periods as $key => $periods) {
foreach ($periods as $period) {
echo "$key : $period[0] -> $period[1]\n";
}
}
输出:
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
我会用一堆嵌套循环来完成
$output = [];
foreach ($all_data as $place => $place_data) {
foreach ($place_data as $innerplace_data) {
$canBeAdded = true;
foreach ($all_data as $otherplace => $otherplace_data) {
if ($place !== $otherplace) {
foreach($otherplace as $innerotherplace_data) {
$canBeAdded = $canBeAdded && (!(($innerotherplace_data[0] > $otherplace_data[1]) || ($innerotherplace_data[1] < $otherplace_data[0])));
}
}
}
if ($canBeAdded) $output[]=$place . " " . $innerplace_data[0] . "->" . $innerplace_data[1];
}
}
未测试。
你在下面找到我的解决方案。测试良好:
class TimeSlots {
private array $cities;
private array $values;
private array $overlaps;
public function __construct(array $data) {
$this->setData($data);
}
/**
* @param $data
*/
public function setData($data): void {
$this->cities = array_keys($data);
$this->overlaps = [];
$this->values = array_map("array_values", array_values($data));
}
/**
* @return void
*/
public function clear(): void {
$this->values = [];
$this->cities = [];
}
public function getOverlaps(): array {
if (!empty($this->overlaps)) {
return $this->overlaps;
}
$result = [];
if (empty($this->cities)) {
return $result;
}
foreach ($this->cities as $position => $city) {
$computed = $this->computeCityOverlap($position);
$result[$city] = $computed;
}
$this->overlaps = $result;
return $this->overlaps;
}
private function computeCityOverlap(int $pos): array {
$current = 0;
return array_reduce($this->values[$pos],function ($carry, $ranges) use ($pos,&$current) {
foreach ($ranges as $index => $range) {
$allRangesFlat = array_filter(array_map(function ($value) use ($index) {
return $value[$index] ?? null;
}, $this->values[$pos]));
//Don't include current range
array_splice($allRangesFlat, $current, 1);
$overlap = $this->inspectOverlap($allRangesFlat, $range);
if (empty($overlap)) {
continue;
}
if(empty($carry[$index])){
$carry[$index] = [];
}
if(empty($start = $carry[$index][0]) || ( $overlap[0] >= max($start, $range[0]))){
$carry[$index][0] = $overlap[0];
}
if(empty($end = $carry[$index][1]) || ($overlap[1] >= max($end, $range[1]) )){
$carry[$index][1] = $overlap[1];
}
}
$current += 1;
return $carry;
}, []);
}
private function inspectOverlap(array $haystack, array $range): array{
if (empty($range[0]) || empty($range[1])) {
return [];
}
$result = array_reduce($haystack, function ($carry, $val) use ($range) {
if (empty($val[0]) || empty($val[1])) {
return $carry;
}
if ($val[0] >= $range[0] && $val[0] <= $range[1]){
$end = min($range[1] , $val[1]);
if (empty($carry[0]) || ($carry[0] >= $val[0] && $carry[0] <= $val[1])) {
$carry[0] = $val[0];
$carry[1] = $carry[1] ? min($end, $carry[1]) : $end;
}
}elseif (($val[1] >= $range[0] && $val[1] <= $range[1])){
$start = max($val[0], $range[0]);
if (empty($carry[1]) || ($carry[1] <= $val[1] && $carry[1] >= $val[0])) {
$carry[1] = $val[1];
$carry[0] = $carry[0] ? min($start, $carry[0]) : $start;
}
}
return $carry;
}, [null, null]);
return array_filter($result);
}
}
$all_data = [
'Chevenez' => [
'41.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459'],
['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'41.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459'],
['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'42.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459'],
['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'42.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459'],
['2022-01-09 04:13:37.49459', '2022-01-09 05:13:37.49459']],
'43.NEwan0' => [['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'43.NEwan1' => [['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'44.NEwan0' => [['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'44.NEwan1' => [['2022-01-09 04:28:37.49459', '2022-01-09 05:13:37.49459']],
],
'Barcelona' => [
'5.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459']],
' 5.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459']],
'16.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459']],
'16.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459']]
]
];
$slots = new TimeSlots($all_data);
$o = $slots->getOverlaps();
foreach ($o as $city => $periods) {
foreach ($periods as $period1) {
echo "$city : $period1[0] -> $period1[1]" . PHP_EOL;
}
}
输出为:
Chevenez : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
我有以下名为 $all_data.
的数组Array
(
[Chevenez] => Array
(
[41.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 03:53:37.49459
[1] => 2022-01-19 04:53:37.49459
)
[1] => Array
(
[0] => 2022-01-09 03:53:37.49459
[1] => 2022-01-09 04:53:37.49459
)
)
[41.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:23:37.49459
[1] => 2022-01-19 05:23:37.49459
)
[1] => Array
(
[0] => 2022-01-09 04:23:37.49459
[1] => 2022-01-09 05:23:37.49459
)
)
[42.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:03:37.49459
[1] => 2022-01-19 04:33:37.49459
)
[1] => Array
(
[0] => 2022-01-09 04:03:37.49459
[1] => 2022-01-09 04:33:37.49459
)
)
[42.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:13:37.49459
[1] => 2022-01-19 05:13:37.49459
)
[1] => Array
(
[0] => 2022-01-09 04:13:37.49459
[1] => 2022-01-09 05:13:37.49459
)
)
)
[Barcelona] => Array
(
[5.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 03:53:37.49459
[1] => 2022-01-19 04:53:37.49459
)
)
[5.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:23:37.49459
[1] => 2022-01-19 05:23:37.49459
)
)
[16.NEwan0] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:03:37.49459
[1] => 2022-01-19 04:33:37.49459
)
)
[16.NEwan1] => Array
(
[0] => Array
(
[0] => 2022-01-19 04:13:37.49459
[1] => 2022-01-19 05:13:37.49459
)
)
)
)
从上面的数组中,我试图获得 Chevenez 和 Barcelona 的重叠时间间隔。假设对于 Chevenez,如果所有键 41.NEwan0、41.NEwan1、42.NEwan0 和 42.NEwan1 都重叠,则只考虑否则不重叠。
我已经尝试了
// Placeholder array to contain the periods when everyone is available.
$periods = [];
foreach($all_data as $key => $data){
// Loop until one of the people has no periods left.
while (count($data) && count(array_filter($data)) == count($data)) {
// Select every person's earliest date, then choose the latest of these
// dates.
$start = array_reduce($data, function($carry, $ranges) {
$start = array_reduce($ranges, function($carry, $range) {
// This person's earliest start date.
return !$carry ? $range[0] : min($range[0], $carry);
});
// The latest of all the start dates.
return !$carry ? $start : max($start, $carry);
});
// Select each person's range which contains this date.
$matching_ranges = array_filter(array_map(function($ranges) use($start) {
return current(array_filter($ranges, function($range) use($start) {
// The range starts before and ends after the start date.
return $range[0] <= $start && $range[1] >= $start;
}));
}, $data));
// Find the earliest of the ranges' end dates, and this completes our
// first period that everyone can attend.
$end = array_reduce($matching_ranges, function($carry, $range) {
return !$carry ? $range[1] : min($range[1], $carry);
});
// Add it to our list of periods.
$periods[$key][] = [$start, $end];
// Remove any availability periods which finish before the end of this
// new period.
array_walk($data, function(&$ranges) use ($end) {
$ranges = array_filter($ranges, function($range) use($end) {
return $range[1] > $end;
});
});
}
}
// Output the answer in the specified format.
foreach ($periods as $key => $period) {
foreach ($period as $period1) {
echo "$key : $period1[0] -> $period1[1]\n";
}
}
但它给了我下面的输出。
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Chevenez : 2022-01-19 04:03:37.49459 -> 2022-01-19 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
但我想要的输出是。
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Chevenez : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
它给了我 Chevenez : 2022-01-19 04:03:37.49459 -> 2022-01-19 04:33:37.49459 在第二行但是应该是 Chevenez : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
@amirreza-noori 我在跟随 arrry 时遇到错误。
$all_data = [
'Chevenez' => [
'41.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459'],
['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'41.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459'],
['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'42.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459'],
['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'42.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459'],
['2022-01-09 04:13:37.49459', '2022-01-09 05:13:37.49459']],
'43.NEwan0' => [['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'43.NEwan1' => [['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'44.NEwan0' => [['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'44.NEwan1' => [['2022-01-09 04:28:37.49459', '2022-01-09 05:13:37.49459']],
],
'Barcelona' => [
'5.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459']],
'5.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459']],
'16.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459']],
'16.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459']]
]
];
所需的输出是。
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
我发现了你对待日期的方式。因此无需将它们转换为浮点数。所以问题是关于算法的。以下代码可能是一个解决方案。
$all_data = [
'Chevenez' => [
'41.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459'],
['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'41.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459'],
['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'42.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459'],
['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'42.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459'],
['2022-01-09 04:13:37.49459', '2022-01-09 05:13:37.49459']],
'43.NEwan0' => [['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'43.NEwan1' => [['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'44.NEwan0' => [['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'44.NEwan1' => [['2022-01-09 04:28:37.49459', '2022-01-09 05:13:37.49459']],
],
'Barcelona' => [
'5.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459']],
'5.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459']],
'16.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459']],
'16.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459']]
]
];
$periods = [];
foreach($all_data as $place => $parts) {
// select first times of each place
$part1_times = $parts[array_key_first($parts)];
$periods[$place] = [];
// walk on times parts
foreach($part1_times as $t => $part1_time_range) {
$range_low = $part1_time_range[0];
$range_up = $part1_time_range[1];
// detect common range
foreach($parts as $part_times) {
if(!isset($part_times[$t])) break;
$rlow = $part_times[$t][0];
$rup = $part_times[$t][1];
if($rlow > $range_low) $range_low = $rlow;
if($rup < $range_up) $range_up = $rup;
}
if($range_low < $range_up) $periods[$place][] = [$range_low, $range_up];
}
// sort times in each place from small to big
usort($periods[$place], function($a, $b) {
return $a[0] > $b[0] ? 1 : -1;
});
}
// Output the answer in the specified format.
foreach ($periods as $key => $periods) {
foreach ($periods as $period) {
echo "$key : $period[0] -> $period[1]\n";
}
}
输出:
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
我会用一堆嵌套循环来完成
$output = [];
foreach ($all_data as $place => $place_data) {
foreach ($place_data as $innerplace_data) {
$canBeAdded = true;
foreach ($all_data as $otherplace => $otherplace_data) {
if ($place !== $otherplace) {
foreach($otherplace as $innerotherplace_data) {
$canBeAdded = $canBeAdded && (!(($innerotherplace_data[0] > $otherplace_data[1]) || ($innerotherplace_data[1] < $otherplace_data[0])));
}
}
}
if ($canBeAdded) $output[]=$place . " " . $innerplace_data[0] . "->" . $innerplace_data[1];
}
}
未测试。
你在下面找到我的解决方案。测试良好:
class TimeSlots {
private array $cities;
private array $values;
private array $overlaps;
public function __construct(array $data) {
$this->setData($data);
}
/**
* @param $data
*/
public function setData($data): void {
$this->cities = array_keys($data);
$this->overlaps = [];
$this->values = array_map("array_values", array_values($data));
}
/**
* @return void
*/
public function clear(): void {
$this->values = [];
$this->cities = [];
}
public function getOverlaps(): array {
if (!empty($this->overlaps)) {
return $this->overlaps;
}
$result = [];
if (empty($this->cities)) {
return $result;
}
foreach ($this->cities as $position => $city) {
$computed = $this->computeCityOverlap($position);
$result[$city] = $computed;
}
$this->overlaps = $result;
return $this->overlaps;
}
private function computeCityOverlap(int $pos): array {
$current = 0;
return array_reduce($this->values[$pos],function ($carry, $ranges) use ($pos,&$current) {
foreach ($ranges as $index => $range) {
$allRangesFlat = array_filter(array_map(function ($value) use ($index) {
return $value[$index] ?? null;
}, $this->values[$pos]));
//Don't include current range
array_splice($allRangesFlat, $current, 1);
$overlap = $this->inspectOverlap($allRangesFlat, $range);
if (empty($overlap)) {
continue;
}
if(empty($carry[$index])){
$carry[$index] = [];
}
if(empty($start = $carry[$index][0]) || ( $overlap[0] >= max($start, $range[0]))){
$carry[$index][0] = $overlap[0];
}
if(empty($end = $carry[$index][1]) || ($overlap[1] >= max($end, $range[1]) )){
$carry[$index][1] = $overlap[1];
}
}
$current += 1;
return $carry;
}, []);
}
private function inspectOverlap(array $haystack, array $range): array{
if (empty($range[0]) || empty($range[1])) {
return [];
}
$result = array_reduce($haystack, function ($carry, $val) use ($range) {
if (empty($val[0]) || empty($val[1])) {
return $carry;
}
if ($val[0] >= $range[0] && $val[0] <= $range[1]){
$end = min($range[1] , $val[1]);
if (empty($carry[0]) || ($carry[0] >= $val[0] && $carry[0] <= $val[1])) {
$carry[0] = $val[0];
$carry[1] = $carry[1] ? min($end, $carry[1]) : $end;
}
}elseif (($val[1] >= $range[0] && $val[1] <= $range[1])){
$start = max($val[0], $range[0]);
if (empty($carry[1]) || ($carry[1] <= $val[1] && $carry[1] >= $val[0])) {
$carry[1] = $val[1];
$carry[0] = $carry[0] ? min($start, $carry[0]) : $start;
}
}
return $carry;
}, [null, null]);
return array_filter($result);
}
}
$all_data = [
'Chevenez' => [
'41.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459'],
['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'41.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459'],
['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'42.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459'],
['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'42.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459'],
['2022-01-09 04:13:37.49459', '2022-01-09 05:13:37.49459']],
'43.NEwan0' => [['2022-01-09 03:53:37.49459', '2022-01-09 04:53:37.49459']],
'43.NEwan1' => [['2022-01-09 04:23:37.49459', '2022-01-09 05:23:37.49459']],
'44.NEwan0' => [['2022-01-09 04:03:37.49459', '2022-01-09 04:33:37.49459']],
'44.NEwan1' => [['2022-01-09 04:28:37.49459', '2022-01-09 05:13:37.49459']],
],
'Barcelona' => [
'5.NEwan0' => [['2022-01-19 03:53:37.49459', '2022-01-19 04:53:37.49459']],
' 5.NEwan1' => [['2022-01-19 04:23:37.49459', '2022-01-19 05:23:37.49459']],
'16.NEwan0' => [['2022-01-19 04:03:37.49459', '2022-01-19 04:33:37.49459']],
'16.NEwan1' => [['2022-01-19 04:13:37.49459', '2022-01-19 05:13:37.49459']]
]
];
$slots = new TimeSlots($all_data);
$o = $slots->getOverlaps();
foreach ($o as $city => $periods) {
foreach ($periods as $period1) {
echo "$city : $period1[0] -> $period1[1]" . PHP_EOL;
}
}
输出为:
Chevenez : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459
Chevenez : 2022-01-09 04:23:37.49459 -> 2022-01-09 04:33:37.49459
Barcelona : 2022-01-19 04:23:37.49459 -> 2022-01-19 04:33:37.49459