digout
digout

Reputation: 4252

How to remove duplicates from PHP multidimensional array, case insensitive but preserving case?

There are many solutions to removing duplicates from multidimensional arrays in PHP but I haven't found one which detects duplicates no matter of case, but preserves them in the output:

// Sample data
$arr  = [
    ['id' => 1, 'term' => 'Hello'],
    ['id' => 1, 'term' => 'hello'],
    ['id' => 2, 'term' => 'Hello'],
    ['id' => 2, 'term' => 'hello']
];

// Desired output
$arr  = [
    ['id' => 1, 'term' => 'Hello'],
    ['id' => 2, 'term' => 'Hello']
];
// Ex 1. case sensitive, preserves case
$serialized = array_map('serialize', $arr);
$unique = array_unique($serialized);
$unique = array_intersect_key($arr, $unique);
// Ex 2. case insensitive, doesn't preserve case
$unique = array_map('unserialize',
    array_unique(
        array_map('strtolower',
            array_map('serialize',$arr)
        )
    )
);

Upvotes: 4

Views: 256

Answers (2)

apokryfos
apokryfos

Reputation: 40653

There's no built-in way. You can however define a custom comparator and a sort:

function compare($a, $b) {
     ksort($a);
     ksort($b); //To ignore keys not in the same order
     return strtolower(serialize($a)) <=> strtolower(serialize($b));
}

function array_unique_callback($arr, $callback) {
    $copy = $arr;
    usort($copy, $callback);
    $previous = null;
    $arr = [];
    foreach ($copy as $key => $value) {
        if ($previous === null || $callback($previous,$value) !== 0) {
            $previous = $value;
            $arr[$key] = $value;
        }
    }
    return $arr;
}

// Sample data
$arr  = [
    ['id' => 1, 'term' => 'Hello'],
    ['id' => 2, 'term' => 'hello'],
    ['id' => 1, 'term' => 'hello'],
    ['id' => 2, 'term' => 'Hello']
];

print_r(array_unique_callback($arr, 'compare'));

Note this will not work for multi-dimensional sub-arrays unless their keys are in the same order. You might need to do a recursive ksort to get that to work.

Working example

Upvotes: 0

Nigel Ren
Nigel Ren

Reputation: 57121

Rather than manipulating the content of the array, this creates a key to the array (in a similar manner to how you manipulate the main array) and then when you combine the key with the data (using array_combine()) the duplicates are removed (as only 1 key can exist in the result)...

$arr  = [
    ['id' => 1, 'term' => 'Hello'],
    ['id' => 1, 'term' => 'hello'],
    ['id' => 1, 'term' => 'Hello'],
    ['id' => 2, 'term' => 'Hello']
];

$key = array_map("serialize", $arr);
$key = array_map("strtolower", $key);
$new = array_combine($key, $arr);

print_r(array_values($new));

gives...

Array
(
    [0] => Array
        (
            [id] => 1
            [term] => Hello
        )

    [1] => Array
        (
            [id] => 2
            [term] => Hello
        )

)

For the vertically challenged, it can be wrapped into 1 (although less readable) line ...

$new = array_values(array_combine(array_map("strtolower", array_map("serialize", $arr)), $arr));

Upvotes: 3

Related Questions