case-insensitive array_unique
Asked Answered
L

5

38

I'm trying to write a few lines of code to make a case insensitive array unique type function. Here's what I have so far:

foreach ($topics as $value) {
    $lvalue = strtolower($value);
    $uvalue = strtolower($value);

    if (in_array($value, $topics) == FALSE || in_array($lvalue, $topics) == FALSE || in_array($uvalue, $topics) == FALSE) {
        array_push($utopics, $value);
    }
}

The trouble is the if statement. I think there's something wrong with my syntax, but I'm relatively new to PHP and I'm not sure what it is. Any help?

Loya answered 16/2, 2010 at 21:7 Comment(0)
L
76
function array_iunique( $array ) {
    return array_intersect_key(
        $array,
        array_unique( array_map( "strtolower", $array ) )
    );
}
Logographic answered 16/2, 2010 at 21:15 Comment(5)
@Pentium10: You should give credit to the source of your solution: php.net/manual/de/function.array-unique.php#78801Stamford
great find Pentium10, strtolower should be in quotes though.Balanchine
Will this support multibyte characters?Severally
@Stamford : php.net/manual/de/function.array-unique.php#78801 has a bug, not the Pentium10 answer ;)Lefebvre
I'd upvote, but for the combination of using a function array_intersect_key that isn't totally obvious, combined with it being a code-only answer. Some comments or links to docs (or both) would be super helpful to describe what this is doing.Reconvert
A
6

You're setting both lvalue and uvalue to the lower case version.

 $uvalue = strtolower($value);

should be

 $uvalue = strtoupper($value);

That said, this might be a little faster. The performance of your function will degrade exponentially, while this will be more or less linear (at a guess, not a comp-sci major...)

<?php

function array_iunique($ar) {
  $uniq = array();
  foreach ($ar as $value)
    $uniq[strtolower($value)] = $value;
  return array_values($uniq);
}
?>
Adelaidaadelaide answered 16/2, 2010 at 21:10 Comment(4)
wow -.- sometimes I guess I just need another pair of eyes. haha thanks! That still doesn't quite do it, though. Not sure what's wrong... The values that are showing up are values that are duplicates (like jQuery and jQuery) both are displaying. But with values that are different (like php and PHP) neither is showing up. Weird...Loya
Nice solution! Only thing that bothers me is that the original array_unique function preserves the keys whereas this does not but I guess it doesn't matter in this case.Cressi
@Tatu it'd be hard to preserve the keys when you're discarding some of the data... which key do you preserve? The first, or the last, or one chosen at random?Adelaidaadelaide
as the manual states: "Note that keys are preserved. array_unique() sorts the values treated as string at first, then will keep the first key encountered for every value, and ignore all following keys."Cressi
C
1

Assuming:

  • you want to retain the first encountered value of any case-insensitive duplicate and
  • all values are strings and will not be mutated if used as keys

Simply populate a new array keyed by the multibyte-safe uppercase version of the value, then re-index after looping.

Code: (Demo)

foreach ($array as $v) {
    $result[mb_strtoupper($v)] ??= $v;
}
var_export(array_values($result));
Cerebrovascular answered 19/6, 2024 at 11:15 Comment(1)
This works really well and it should be upvoted a lot more. Thank you for this. Exactly what I needed.Danyelldanyelle
R
0

Should $uvalue not be uppercase? So

$uvalue = strtoupper($value):
Roberts answered 16/2, 2010 at 21:12 Comment(0)
B
0

and another alternative...

function array_iunique($topics) {

    $ltopics = array_map('strtolower', $topics);
    $cleanedTopics = array_unique($ltopics);

    foreach($topics as $key => $value) {
        if(!isset($cleanedTopics[$key])) {
            unset($topics[$key]);
        }
    }

    return $topics;

}

Pentium10's is better though.

Brittain answered 16/2, 2010 at 21:27 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.