Hola
Hola

Reputation: 23

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'],
        ];
    }
}

Upvotes: 0

Views: 67

Answers (2)

mickmackusa
mickmackusa

Reputation: 48031

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,
  ),
)

Upvotes: 1

Oluwasegun Ige
Oluwasegun Ige

Reputation: 54

Firstly, loop through the array, keep track of the current date range, and compare the MinStay value with the previous one

If they are the same, extend the range, otherwise, push the current range to the output and start a new one.

$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],
];

$output = [];
$currentRange = null; // Will store the current range of dates

foreach ($input as $date) {
    // If currentRange is empty, start a new range
    if ($currentRange === null) {
        $currentRange = [
            'dateForm' => $date['date'],
            'dateTo' => $date['date'],
            'MinStay' => $date['MinStay'],
        ];
    } else {
        // Check if MinStay matches the current range's MinStay
        if ($date['MinStay'] === $currentRange['MinStay']) {
            // Extend the date range
            $currentRange['dateTo'] = $date['date'];
        } else {
            // If MinStay changes, push the current range to the output
            $output[] = $currentRange;

            // Start a new range
            $currentRange = [
                'dateForm' => $date['date'],
                'dateTo' => $date['date'],
                'MinStay' => $date['MinStay'],
            ];
        }
    }
}

// Add the last range to the output
if ($currentRange !== null) {
    $output[] = $currentRange;
}

// Output the result
print_r($output);

Upvotes: 0

Related Questions