Search code examples
phparraysgroupingdate-rangecontiguous

Group 2d array of dates and values by contiguous dates with the same value


I have a date range 2023-11-01 to 2024-01-04 and some date have different MinStay value.

This is my array of date range

$input = [
  [ 'date' => '2023-11-01', 'MinStay' => 1 ],
  [ 'date' => '2023-11-02', 'MinStay' => 1 ],
  [ 'date' => '2023-11-03', 'MinStay' => 1 ],
  [ 'date' => '2023-11-04', 'MinStay' => 2 ],
  [ 'date' => '2023-11-05', 'MinStay' => 2 ],
  [ 'date' => '2023-11-06', 'MinStay' => 2 ],
  [ 'date' => '2023-12-10', 'MinStay' => 1 ],
  [ 'date' => '2023-12-11', 'MinStay' => 1 ],
  [ 'date' => '2023-12-12', 'MinStay' => 3 ],
  [ 'date' => '2023-12-13', 'MinStay' => 2 ],
  [ 'date' => '2023-12-14', 'MinStay' => 2 ],
  [ 'date' => '2024-01-01', 'MinStay' => 4 ],
  [ 'date' => '2024-01-02', 'MinStay' => 4 ],
  [ 'date' => '2024-01-03', 'MinStay' => 4 ],
  [ 'date' => '2024-01-04', 'MinStay' => 4 ],
];

And I want to

$output = [
  [ 'dateForm' => '2023-11-01', 'dateTo' => '2023-11-03', 'MinStay' => 1 ],
  [ 'dateForm' => '2023-11-04', 'dateTo' => '2023-11-06', 'MinStay' => 2 ],
  [ 'dateForm' => '2023-12-10', 'dateTo' => '2023-12-11', 'MinStay' => 1 ],
  [ 'dateForm' => '2023-12-12', 'dateTo' => '2023-12-12', 'MinStay' => 3 ],
  [ 'dateForm' => '2023-12-13', 'dateTo' => '2023-12-14', 'MinStay' => 2 ],
  [ 'dateForm' => '2024-01-01', 'dateTo' => '2024-01-04', 'MinStay' => 4 ],
];

How can I solve this issue.

I'm try using this array but it's not happening.

$arr = [];
foreach ($input as $date) {
    if ($date['MinStay'] == 1) {
        $arr[] = [
            'dateFrom' => $date['date'],
            'dateTo' => $date['date'],
            'MinStay' => $date['MinStay'],
        ];
    }
}

Solution

  • For maximum elegance, push reference variables into the result array and only update the current reference.

    Your input data was insufficiently challenging to expose solutions which do not factor contiguous dates. I've extended the sample input.

    $input = [
      [ 'date' => '2023-11-01', 'MinStay' => 1 ],
      [ 'date' => '2023-11-02', 'MinStay' => 1 ],
      [ 'date' => '2023-11-03', 'MinStay' => 1 ],
      [ 'date' => '2023-11-04', 'MinStay' => 2 ],
      [ 'date' => '2023-11-05', 'MinStay' => 2 ],
      [ 'date' => '2023-11-06', 'MinStay' => 2 ],
      [ 'date' => '2023-12-10', 'MinStay' => 1 ],
      [ 'date' => '2023-12-11', 'MinStay' => 1 ],
      [ 'date' => '2023-12-12', 'MinStay' => 3 ],
      [ 'date' => '2023-12-13', 'MinStay' => 2 ],
      [ 'date' => '2023-12-14', 'MinStay' => 2 ],
      [ 'date' => '2023-12-24', 'MinStay' => 2 ],  // <-- added challenge where same minstay is not on contiguous date
      [ 'date' => '2024-01-01', 'MinStay' => 4 ],
      [ 'date' => '2024-01-02', 'MinStay' => 4 ],
      [ 'date' => '2024-01-03', 'MinStay' => 4 ],
      [ 'date' => '2024-01-04', 'MinStay' => 4 ],
    ];
    

    Code: (Demo)

    $result = [];
    $lastMinStay = null;
    foreach ($input as ['date' => $d, 'MinStay' => $ms]) {
        if ($ms !== $lastMinStay || $d !== date('Y-m-d', strtotime("{$ref['dateTo']} +1 day"))) {
            unset($ref);
            $ref = ['dateFrom' => $d, 'dateTo' => $d, 'MinStay' => $ms];
            $result[] =& $ref;
            $lastMinStay = $ms;
            continue;
        }
        $ref['dateTo'] = $d;
    }
    var_export($result);
    

    Output:

    array (
      0 => 
      array (
        'dateFrom' => '2023-11-01',
        'dateTo' => '2023-11-03',
        'MinStay' => 1,
      ),
      1 => 
      array (
        'dateFrom' => '2023-11-04',
        'dateTo' => '2023-11-06',
        'MinStay' => 2,
      ),
      2 => 
      array (
        'dateFrom' => '2023-12-10',
        'dateTo' => '2023-12-11',
        'MinStay' => 1,
      ),
      3 => 
      array (
        'dateFrom' => '2023-12-12',
        'dateTo' => '2023-12-12',
        'MinStay' => 3,
      ),
      4 => 
      array (
        'dateFrom' => '2023-12-13',
        'dateTo' => '2023-12-14',
        'MinStay' => 2,
      ),
      5 => 
      array (
        'dateFrom' => '2023-12-24',
        'dateTo' => '2023-12-24',
        'MinStay' => 2,
      ),
      6 => 
      array (
        'dateFrom' => '2024-01-01',
        'dateTo' => '2024-01-04',
        'MinStay' => 4,
      ),
    )