WatsMyName
WatsMyName

Reputation: 4478

Split multidimensional arrays according to date in child array

I have following multidimensional array of dates

array(
    0  => array("TransDate" => "2019-10-28 08:31:02", "Amount" => "12.00"),
    1  => array("TransDate" => "2019-10-28 09:09:14", "Amount" => "12.00"),
    2  => array("TransDate" => "2019-10-28 09:17:14", "Amount" => "12.00"),
    3  => array("TransDate" => "2019-10-28 09:30:14", "Amount" => "12.00"),
    4  => array("TransDate" => "2019-10-28 09:35:14", "Amount" => "12.00"),
    5  => array("TransDate" => "2019-10-28 10:50:14", "Amount" => "12.00"),
    6  => array("TransDate" => "2019-10-28 10:58:14", "Amount" => "12.00"),
    7  => array("TransDate" => "2019-10-28 10:58:14", "Amount" => "12.00"),
    8  => array("TransDate" => "2019-10-28 11:40:14", "Amount" => "12.00"),
    9  => array("TransDate" => "2019-10-28 11:49:14", "Amount" => "12.00"),
    10 => array("TransDate" => "2019-10-28 23:50:14", "Amount" => "12.00")
);

Requirement.

The above array is needed to be splitted into chunks so that each chunk will have elements that have TransDate within a 60 minutes.

the following chunks will throw more light on what actually is needed as a result.

Needed Result

First Chunk

//index 1 through index 3, the TransDate, they all are under 60 minutes difference from index 0
    array(
        0  => array("TransDate" => "2019-10-28 08:31:02", "Amount" => "12.00"),
        1  => array("TransDate" => "2019-10-28 09:09:14", "Amount" => "12.00"),
        2  => array("TransDate" => "2019-10-28 09:17:14", "Amount" => "12.00"),
        3  => array("TransDate" => "2019-10-28 09:30:14", "Amount" => "12.00")
    );

Second Chunk

//the date is more than 60 minutes from the last element of the previous chunk. 
//As we don't have anything that falls within 60 minutes from 
//2019-10-28 09:35:14 (first element below), this chunk will have only one element
array(
    0  => array("TransDate" => "2019-10-28 09:35:14", "Amount" => "12.00"),
);

Third Chunk

//index 1 through index 4, they all are under 60 minutes difference from index 0
array(
    0  => array("TransDate" => "2019-10-28 10:50:14", "Amount" => "12.00"),
    1  => array("TransDate" => "2019-10-28 10:58:14", "Amount" => "12.00"),
    2  => array("TransDate" => "2019-10-28 10:58:14", "Amount" => "12.00"),
    3  => array("TransDate" => "2019-10-28 11:40:14", "Amount" => "12.00"),
    4  => array("TransDate" => "2019-10-28 11:49:14", "Amount" => "12.00")
);

Fourth Chunk

//There are no elements that is under 60 minute difference from first element below, 
//on that particular day 28th October, we'll have just one element.
array(
    0 => array("TransDate" => "2019-10-28 23:50:14", "Amount" => "12.00")
);

Can anybody help me on this how to achieve this?? Thanks

Upvotes: 0

Views: 111

Answers (1)

04FS
04FS

Reputation: 5820

You can do this by simply increasing a counter to use as index on your first level of the result array - and then you simply append the items to the array under that counter.

Every time that counter gets increased, you also set the start date to compare to, to the current item’s start date, so that it marks the start of the current interval.

$output = [];
$c = -1;
$start = null;

foreach($input as $item) {
  if(!$start || strtotime($item['TransDate']) - $start > 60*60) {
    $c++;  
    $start = strtotime($item['TransDate']);
  }
  $output[$c][] = $item;
}

Demo: https://3v4l.org/12TFF

The actual timestamp comparison could probably use a little more finesse than just using strtotime and comparing the difference to 3600 seconds (might lead into trouble with DST for example) - but the basic principle is just that simple.

Your input array of course needs to be correctly sorted by ascending start dates already, if that’s not a given, see to it that you do that first.

Upvotes: 2

Related Questions