phparraysmultidimensional-arrayfilteringgrouping

Reduce 2d array of change history to initial and final values per id and remove rows where no change


There is an array of "movements" of elements, about the same, only it can be many times more:

Array
(
    [0] => Array
        (
            [id] => 90415
            [oldDate] => 2024-08-27
            [newDate] => 2024-08-28
        )

    [1] => Array
        (
            [id] => 90415
            [oldDate] => 2024-08-28
            [newDate] => 2024-08-27
        )

    [2] => Array
        (
            [id] => 90409
            [oldDate] => 2024-08-21
            [newDate] => 2024-08-22
        )

    [3] => Array
        (
            [id] => 90409
            [oldDate] => 2024-08-22
            [newDate] => 2024-08-23
        )
)

I'm trying to make sure that all the intermediate movements of the element are deleted, only the initial and final ones remain, and the elements of the array are deleted, where the element is returned to its original position (0 and 1 elements of the array). In the end, the processed array should look like this:

Array
(
    [0] => Array
        (
            [id] => 90409
            [oldDate] => 2024-08-21
            [newDate] => 2024-08-23
        )
)

how can I do this so that an array of a large number of elements does not delay the script for a long time


Solution

  • Here is a solution that uses an intermediate $data associative array, which allows efficient lookups:

    $moves = [
        ['id' => 90415, 'oldDate' => '2024-08-27', 'newDate' => '2024-08-28'],
        ['id' => 90415, 'oldDate' => '2024-08-28', 'newDate' => '2024-08-27'],
        ['id' => 90409, 'oldDate' => '2024-08-21', 'newDate' => '2024-08-22'],
        ['id' => 90409, 'oldDate' => '2024-08-22', 'newDate' => '2024-08-23'],
        ];
    
    $data = [];
    foreach($moves as $move)
    {
        $id = $move['id'];
        if(isset($data[$id]))
        {
            // Id already present, update its newDate
            $data[$id]['newDate'] = $move['newDate'];
        }
        else
        {
            // New id, store it
            $data[$id] = $move;
        }
    }
    
    // Keep ids with different oldDate and newDate
    $result = array_filter($data, fn($move) => $move['oldDate'] != $move['newDate']);
    
    // Remove array keys
    $result = array_values($result);
    
    var_export($result);
    

    Output:

    array (
      0 => 
      array (
        'id' => 90409,
        'oldDate' => '2024-08-21',
        'newDate' => '2024-08-23',
      ),
    )