12

I would like to remove duplicates by value as you can see from the list_title. I know there are several questions and answers to this but their solution doesn't work for me.

Here is what I've tried:

$uniqueArray = array_map("unserialize", array_unique(array_map("serialize", $notify)));

Result:

Array
(
[0] => Array
    (
        [list_id] => 86
        [list_reference] => 130948
        [list_title] => Offer:  apartment 2+kk 
        [list_city] => Prague
        [list_date] => 2017-03-03 11:20:35
        [list_status] => 0
        [list_creator] => Company A
        [list_price] => 30000
        [list_furniture] => ["1","0","0"]
        [list_accommodation] => flat
    )

[1] => Array
    (
        [list_id] => 87
        [list_reference] => 130947
        [list_title] => Offer:  apartment 2+kk 
        [list_date] => 2017-03-03 11:20:35
        [list_status] => 0
        [list_creator] => Company B
        [list_price] => 30000
        [list_furniture] => ["1","0","0"]
        [list_accommodation] => flat
    )

[2] => Array ...

Expected result should be one of those because of the title:

Array
(
[0] => Array
(
    [list_id] => 86
    [list_reference] => 130948
    [list_title] => Offer:  apartment 2+kk 
    [list_city] => Prague
    [list_date] => 2017-03-03 11:20:35
    [list_status] => 0
    [list_creator] => Company A
    [list_price] => 30000
    [list_furniture] => ["1","0","0"]
    [list_accommodation] => flat
)
Shina
  • 2,019
  • 2
  • 19
  • 25

3 Answers3

13

So basically you want to remove duplicates by 'list_title' column. Let's assume we keep the first occurrence of this title. Then you can use a couple of standard functions to achieve this:

// Reverse array, so the first occurrence kept.
$data = array_reverse($data);

$result = array_reverse( // Reverse array to the initial order.
    array_values( // Get rid of string keys (make array indexed again).
        array_combine( // Create array taking keys from column and values from the base array.
            array_column($data, 'list_title'), 
            $data
        )
    )
);

Here is working demo.

UPDATE:

Based on @mickmackusa comment, the code can be simplified to:

$result = array_reverse(array_values(array_column(
    array_reverse($data),
    null,
    'list_title'
)));

This is described in the docs regarding column_key parameter specs:

It may also be NULL to return complete arrays or objects (this is useful together with index_key to reindex the array).

sevavietl
  • 3,762
  • 1
  • 14
  • 21
  • 2
    `array_column()` is smarter than this. Don't use `array_combine()`. See what happens when you set the 2nd parameter of `array_column()` to `null`. – mickmackusa May 23 '18 at 03:54
  • Could someone explain to me how the updated solution works? I'm lost. – Yousof K. Mar 06 '19 at 21:14
  • 1
    @YousofK. well, `array_column` will reindex array by `list_title`. That means that for the same `list_titles` the last item will override all previous. But we want the first item, not the last. So we use `array_reverse` to reverse an array in the beginning and reverse it back at the end. – sevavietl Mar 12 '19 at 14:46
5

Thanks everyone, sometimes over-thinking can affect common sense.

I simply solved it from MYSQL query with something like:

 GROUP BY list_title ORDER BY list_date
Shina
  • 2,019
  • 2
  • 19
  • 25
0

Just loop through the arrays and keep track of duplicate field entries.

Only the list_id and list_title will be considered for duplicate arrays but extra fields can be added. All the other keys are ignored.

<?php

$array = [
    [
        "list_id" => 86,
        "list_reference" => 130948,
        "list_title" => "Offer:  apartment 2+kk",
        "list_city" => "Prague",
        "list_date" => "2017-03-03 11:20:35",
        "list_status" => 0,
        "list_creator" => "Company A",
        "list_price" => 30000,
        "list_furniture" => '""1","0","0""',
        "list_accommodation" => "flat"
    ],
    [
        "list_id" => 87,
        "list_reference" => 130947,
        "list_title" => "Offer:  apartment 2+kk", 
        "list_date" => "2017-03-03 11:20:35",
        "list_status" => 0,
        "list_creator" => "Company B",
        "list_price" => 30000,
        "list_furniture" => '""1","0","0""',
        "list_accommodation" => "flat"
    ]
];


$duplicateFields = ["list_id" => array(), "list_title" => array()];
foreach ($array as $index => $value) {
    if(in_array($value['list_id'], $duplicateFields['list_id']) || in_array($value['list_title'], $duplicateFields['list_title'])){
        unset($array[$index]);
    }else{
        array_push($duplicateFields['list_id'], $value['list_id']);
        array_push($duplicateFields['list_title'], $value['list_title']);
    }
}

var_dump($array);

Which yields:

array(1) {
  [0]=>
  array(10) {
    ["list_id"]=>
    int(86)
    ["list_reference"]=>
    int(130948)
    ["list_title"]=>
    string(22) "Offer:  apartment 2+kk"
    ["list_city"]=>
    string(6) "Prague"
    ["list_date"]=>
    string(19) "2017-03-03 11:20:35"
    ["list_status"]=>
    int(0)
    ["list_creator"]=>
    string(9) "Company A"
    ["list_price"]=>
    int(30000)
    ["list_furniture"]=>
    string(13) """1","0","0"""
    ["list_accommodation"]=>
    string(4) "flat"
  }
}
Roy
  • 3,027
  • 4
  • 29
  • 43
  • Making iterated `in_array()` calls is one of the most expensive ways to filter an array. This technique becomes proportionately unsavory as the size of the arrays increase. `in_array()` is a relatively slow technique because it cannot enjoy the performance benefits of searching by keys. – mickmackusa Oct 13 '21 at 08:02