0

I have a PHP array with indexes, its values can be duplicated. I want to remove all duplicated indexes from this array:

array(3) {
  [0]=>
  array(5) {
    ["uid"]=>
    int(1)
    ["title"]=>
    string(26) "Title A"
    ["tstamp"]=>
    string(10) "1580296755"
  }
  [1]=>    // <----- should be removed, because it's tstamp is lower than it's duplicate
  array(5) {
    ["uid"]=>
    int(2)
    ["title"]=>
    string(33) "Title B"   // <----- duplicate value
    ["tstamp"]=>
    string(10) "1580296797"
  }
  [2]=>
  array(5) {
    ["uid"]=>
    int(3)
    ["title"]=>
    string(33) "Title B"   // <----- duplicate value
    ["tstamp"]=>
    string(10) "1580298366"
  }
}

So, Index 1 and 2 with the same title "Title B" are duplicated. Only the one with the higher tstamp should be exists, all older ones with same title should be removed from array:

array(3) {
  [0]=>
  array(5) {
    ["uid"]=>
    int(1)
    ["title"]=>
    string(26) "Title A"
    ["tstamp"]=>
    string(10) "1580296755"
  }
  [1]=>
  array(5) {
    ["uid"]=>
    int(3)
    ["title"]=>
    string(33) "Title B"
    ["tstamp"]=>
    string(10) "1580298366"
  }
}

Hope someone understand me and can help to solve my problem.

3 Answers 3

2

I don't believe you're actual concern here is the array keys, as your questions posits. I believe your real concern is in preventing duplicate values. If the array were sorted by the 'tstamp key this would be a simple column pluck operation.

So assuming ...

$arr = [
    ['uid' => 1, 'title' => 'Title A', 'tstamp' => 1580296755],
    ['uid' => 2, 'title' => 'Title B', 'tstamp' => 1580296797],
    ['uid' => 3, 'title' => 'Title B', 'tstamp' => 1580298366],
];

// Sorted ascendingly by 'tstamp' key
uasort($arr, function($a, $b) { return $a['tstamp'] <=> $b['tstamp']; });

// Pluck the title and overwriting is automatic
$result = array_column($arr, null, 'title');

var_dump($result);

The result would be:

array(2) {
  ["Title A"]=>
  array(3) {
    ["uid"]=>
    int(1)
    ["title"]=>
    string(7) "Title A"
    ["tstamp"]=>
    int(1580296755)
  }
  ["Title B"]=>
  array(3) {
    ["uid"]=>
    int(3)
    ["title"]=>
    string(7) "Title B"
    ["tstamp"]=>
    int(1580298366)
  }
}
Sign up to request clarification or add additional context in comments.

Comments

1

Just create an empty array, loop through your old array and add them to the new array with the key as the title.

<?php

$old = [
    ['uid' => 1, 'title' => 'Title A', 'tstamp' => 1580296755],
    ['uid' => 2, 'title' => 'Title B', 'tstamp' => 1580296797],
    ['uid' => 3, 'title' => 'Title B', 'tstamp' => 1580298366],
];

$new = [];
foreach($old as $row) {

    $title = $row['title'];

    //check if title exists as key of `$new` array.
    //if it does exist as a key, check if `tstamp` in the loop is higher than the existing record
    if(!array_key_exists($title, $new) || ($new[$title]['tstamp'] < $row['tstamp'])) {

        //update or insert record if the if-statement evaluates to true
        $new[$title] = $row;
    }
}

Output:

Array
(
    [Title A] => Array
        (
            [uid] => 1
            [title] => Title A
            [tstamp] => 1580296755
        )

    [Title B] => Array
        (
            [uid] => 3
            [title] => Title B
            [tstamp] => 1580298366
        )

)

This has the added benefit of being able to select titles easier, for example $new['Title A']. If you want the key indexes to still be numerical, you can use $new = array_values($new); to do so. If you use array_values(), the output matches your expected output exactly.

Comments

0

You can use in_array function in such way:

$tmp = [];

foreach($ar as $ind=>$set){
    if(!in_array($set['title'],$tmp)){
        $tmp[] = $set['title'];
    } else {
        unset($ar[$ind]);
    } 
}

print_r($ar);

Demo

Output:

Array
(
    [0] => Array
        (
            [uid] => 1
            [title] => Title A
            [tstamp] => 1580296755
        )

    [1] => Array
        (
            [uid] => 2
            [title] => Title B
            [tstamp] => 1580296755
        )

    [3] => Array
        (
            [uid] => 4
            [title] => Title C
            [tstamp] => 1580296755
        )

)

or if you need to leave the last one appearance you can use next code:

$tmp = [];
$res = [];

foreach($ar as $ind=>$set){ 
    $tmp[$set['title']] = $ind; 
}

foreach($tmp as $title=>$ind){ 
    $res[] = $ar[$ind];
}

print_r($res);

Demo

Output:

Array
(
    [0] => Array
        (
            [uid] => 1
            [title] => Title A
            [tstamp] => 1580296755
        )

    [1] => Array
        (
            [uid] => 3
            [title] => Title B
            [tstamp] => 1580296755
        )

    [2] => Array
        (
            [uid] => 4
            [title] => Title C
            [tstamp] => 1580296755
        )

)

3 Comments

This only works if the newest tstamp is always later in the array, which may not be the case
@GrumpysaysReinstateMonica, it's possible that tstamps could be shaffled? Why that wasn't mentioned that in question? I see that's your data would be always sorted by id and tstamp in ASC order.
@AksenP It's not my question. But OP didn't specify if the timestamps are always in order, so I assumed that there is no guarantee that they are in order instead of assuming they will always be in order. In any case, my comment is not saying that your answer is wrong, it's just a disclaimer that it won't work if the tstamp isn't always in order, which is probably perfectly fine for someone else who may see this question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.