phparraysfilterassociative-array

Filter php array and keep only oldest data on duplicate data


I've an array in PHP that can have multiple same labels, but creation date for each one is different. I try to filter my array and keep only old created data when duplicates labels exists in my array.

The array look like this :

$data = [
     [0] => Array
        (
            [label] => "Same label"
            [created] => "15/01/2022" //recent data
        )
     [1] => Array
        (
            [label] => "Same label"
            [created] => "11/01/2022" //oldest data to unset
        )
     [2] => Array
        (
            [label] => "Label alone"
            [created] => "18/01/2022"
        )
]

And have to be like this :

$data = [
     [0] => Array
        (
            [label] => "Same label"
            [created] => "11/01/2022"
        )
     [1] => Array
        (
            [label] => "Label alone"
            [created] => "18/01/2022"
        )
]

Actually, I've tried with an array_search() but process is long if they are a lot of data. I can remove duplicate data but I don't know how to filter by created date only on duplicate labels in my array...

$data = [];
foreach ($prs as $pr) {
  $exist = array_search($pr->getLabel, array_column($data, 'label'), TRUE);

  if (!$exist){
    $data[] = [
          'label' => $pr->getLabel(),
          'created' => $pr->getCreationDate(),
    ];
  }
}

I saw that there are also array_filter() function, array_key_exists() and other good functions.

Can you help me please ?

I'll add more info as I progress, but I can't show all page or processes (just example because they are confidential data).

Thank you a lot for your help.


Solution

  • One way might be doing a dual sort by label and by date. Then after sorting, you can loop the collection and compare the current and the next label.

    If the next label is different from the current or the last one in the collection, then add the item to the $result array.

    The example uses a spaceship operator <=> for the comparison in the usort function and is available since php 7

    $data = [
        ["label" => "test1","created" => "31/12/2022"],
        ["label" => "Same label", "created" => "13/01/2022"],
        ["label" => "Same label", "created" => "15/01/2022"],
        ["label" => "Same label", "created" => "11/01/2022"],
        ["label" => "Label alone","created" => "18/01/2022"],
        ["label" => "test1","created" => "30/12/2022"],
    ];
    
    usort($data, function($a, $b) {
        if ($a["label"] === $b["label"]) {
            return DateTime::createFromFormat("d/m/Y", $a["created"]) <=> DateTime::createFromFormat("d/m/Y", $b["created"]);
        }
        return $a["label"] <=> $b["label"];
    });
    
    $result = [];
    $last = count($data) - 1;
    
    for ($i = 0; $i < count($data); $i++) {
        if ((isset($data[$i + 1]) && $data[$i + 1]["label"] !== $data[$i]["label"]) || $i === $last) {
            $result[] = $data[$i];
        }
    }
    
    print_r($result);
    

    Output

    Array
    (
        [0] => Array
            (
                [label] => Label alone
                [created] => 18/01/2022
            )
    
        [1] => Array
            (
                [label] => Same label
                [created] => 15/01/2022
            )
    
        [2] => Array
            (
                [label] => test1
                [created] => 31/12/2022
            )
    
    )
    

    See a PHP demo.