从一个数组中返回重复的条目(忽略大小写)

36

我想从一个数组中检索出所有不区分大小写的重复项。在PHP中是否有可能实现?

array(
    1 => '1233',
    2 => '12334',
    3 => 'Hello',
    4 => 'hello',
    5 => 'U'
);

期望的输出数组:

array(
    1 => 'Hello',
    2 => 'hello'
);

这里有一个类似的问题:https://dev59.com/dXM_5IYBdhLWcg3w02z8#1212863 - Till Theis
7个回答

41
function get_duplicates ($array) {
    return array_unique( array_diff_assoc( $array, array_unique( $array ) ) );
}

第一个 array_unique 真的需要吗?没有它,似乎得到了相同的结果。 - luukvhoudt
我认为如果没有第一个 array_unique,原始数组中有一个值出现了三次,返回的数组将会出现两次;或者如果原始数组中有四个相同的值,返回的数组中将只有三个。 - 75th Trombone
1
以上的评论说明了在答案中解释代码的重要性。 - mickmackusa

27
<?php
function array_not_unique($raw_array) {
    $dupes = array();
    natcasesort($raw_array);
    reset($raw_array);

    $old_key   = NULL;
    $old_value = NULL;
    foreach ($raw_array as $key => $value) {
        if ($value === NULL) { continue; }
        if (strcasecmp($old_value, $value) === 0) {
            $dupes[$old_key] = $old_value;
            $dupes[$key]     = $value;
        }
        $old_value = $value;
        $old_key   = $key;
    }
    return $dupes;
}

$raw_array    = array();
$raw_array[1] = 'abc@xyz.com';
$raw_array[2] = 'def@xyz.com';
$raw_array[3] = 'ghi@xyz.com';
$raw_array[4] = 'abc@xyz.com'; // Duplicate

$common_stuff = array_not_unique($raw_array);
var_dump($common_stuff);

如果我们在使用之前使用 array_map("serialize", $arr);,那么对于二维数组也是一个不错的解决方案。谢谢! - Boolean_Type

21

为了得到你想要的 "Hello" => "hello" 的结果,你需要将函数不区分大小写。可以尝试使用以下方法:

$arr = array(1=>'1233',2=>'12334',3 =>'Hello' ,4=>'hello', 5=>'U');

// Convert every value to uppercase, and remove duplicate values
$withoutDuplicates = array_unique(array_map("strtoupper", $arr));

// The difference in the original array, and the $withoutDuplicates array
// will be the duplicate values
$duplicates = array_diff($arr, $withoutDuplicates);
print_r($duplicates);

输出结果为:

Array
(
[3] => Hello
[4] => hello
)

编辑者 @AlixAxel:

这个答案非常误导人,它只在特定情况下有效。以下是一个反例:

$arr = array(1=>'1233',2=>'12334',3 =>'Hello' ,4=>'HELLO', 5=>'U');

失败了。而且,这不是保留重复项的方法:

array_diff($arr, array_unique($arr));

由于重复的值之一将在 array_unique 中,并且随后被 array_diff 剪掉。

@RyanDay编辑:

因此,请查看 @Srikanth 或 @Bucabay 的答案,它们适用于所有情况(在 Bucabay 的答案中寻找不区分大小写),而不仅仅是问题中指定的测试数据。


你需要使用array_diff_key(),否则你将返回原始数组中不是大写字母的每个值。 - bucabay
非常干净和逻辑清晰。首先只获取唯一的元素并与原始数组进行比较。 - Jamol
1
@rday - 注意你的测试主体包含数字和大写字母“U”,而这些字符在strtoupper()函数中都是大写的。返回结果是strtoupper()修改后的混合大小写值,而不是重复项。如果发布者需要两个重复项,则约翰提出的解决方案将以O(n)的时间复杂度高效完成工作,我相信这是最佳情况。 - bucabay
7
这是一个彻头彻尾的失败:http://codepad.org/7NQ9lQLU。仅凭运气才能工作。 - Alix Axel
3
浪费了我15分钟,本应该看到@AkshatSinghal的评论。 - mokNathal
显示剩余4条评论

8
这是做法正确的方式(要区分大小写):
array_intersect($arr, array_unique(array_diff_key($arr, array_unique($arr))));

以下是不区分大小写的解决方案:

$iArr = array_map('strtolower', $arr);
$iArr = array_intersect($iArr, array_unique(array_diff_key($iArr, array_unique($iArr))));

array_intersect_key($arr, $iArr);

但是@Srikanth的答案更高效(实际上,除了这个答案以外,它是唯一一个正确工作的)。


好的,我来解决。我的解决方案有错误,但是你的解决方案没有返回OP所寻找的值。我不明白为什么我的答案是一个惨败,而你的更好? - ryanday
@ryanday:我的程序以区分大小写的方式完成工作,并且可以适应不区分大小写的情况。而你的回答几乎和“return array(1 =>'Hello' ,2=>'hello');”一样有用。我希望你能理解我的意思… - Alix Axel
@ryanday:添加了一个不区分大小写的版本。 - Alix Axel

7
function array_not_unique($raw_array) {
    $dupes = array();
    natcasesort($raw_array);
    reset($raw_array);

    $old_key   = NULL;
    $old_value = NULL;
    foreach ($raw_array as $key => $value) {
        if ($value === NULL) { continue; }
        if (strcasecmp($old_value, $value) === 0) {
            $dupes[$old_key] = $old_value;
            $dupes[$key]     = $value;
        }
        $old_value = $value;
        $old_key   = $key;
    } return $dupes;
}

Srikanth(约翰)添加了大小写不敏感的比较方式。


6

尝试:

$arr2 = array_diff_key($arr, array_unique($arr));

不区分大小写:
array_diff_key($arr, array_unique(array_map('strtolower', $arr)));

4
其中一个重复的值将被删除,不会返回所有的重复值。 - Alix Axel

0

这是一篇12年前的帖子,被采纳的答案返回一个空数组,其他答案则过于冗长。

以下是我对未来的谷歌搜索者的建议,它简短明了,并且返回所有重复的索引(Indices?)。

$myArray = array('fantastic', 'brilliant', 'happy', 'fantastic', 'Happy', 'wow', 'battlefield2042 :(');

function findAllDuplicates(array $array)
{
    // Remove this line if you do not need case sensitive.
    $array = array_map('strtolower', $array);

    // Remove ALL duplicates
    $removedDuplicates = array_diff($array, array_diff_assoc($array, array_unique($array)));

    return array_keys(array_diff($array, $removedDuplicates));
    // Output all keys with duplicates
    // array(4) {
    //   [0]=>int(0)
    //   [1]=>int(2)
    //   [2]=>int(3)
    //   [3]=>int(4)
    // }


    return array_diff($array, $removedDuplicates);
    // Output all duplicates
    // array(4) {
    //   [0]=>string(9) "fantastic"
    //   [2]=>string(5) "happy"
    //   [3]=>string(9) "fantastic"
    //   [4]=>string(5) "happy"
    // }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接