如何从PHP中的多维数组中删除重复值?

示例数组:

Array
(
    [0] => Array
    (
        [0] => abc
        [1] => def
    )

    [1] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [2] => Array
    (
        [0] => mno
        [1] => pql
    )

    [3] => Array
    (
        [0] => abc
        [1] => def
    )

    [4] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [5] => Array
    (
        [0] => mno
        [1] => pql
    )

)


#1 楼

这是另一种方式。没有保存中间变量。

我们用它来消除来自各种重叠查询的结果。

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));


评论


由于反序列化,阵列变得越来越大,越来越复杂,它变得越来越慢。我使用array_intersect_key(此答案之前半年)是有原因的。

– OIS
13年2月8日在23:00

@OIS刚刚测试了它,有一个错字,但它可以工作..谢谢花花公子!

– Trevorkavanaugh
13年6月3日在20:26

如果您希望索引连续,请使用array_values,即$ input = array_values(array_map(“ unserialize”,array_unique(array_map(“ serialize”,$ input)))));

–lbsweek
2014年4月17日在10:44



如今,您可能会选择json_encode和json_decode而不是PHP序列化。应该可以从提供的值中受益,并且您不会遇到PHP序列化详细信息,该序列化附带了对序列化/反序列化的附带信息,并且很可能是不需要的。

– hakre
2014年8月23日在13:38



请注意serialize(array('a'=>'1','b'=>'1'))与serialize(array('b'=>'1','a'=>'1')不同)。对于用作集合或(哈希)映射的数组,此选项将失败。

– Andras Gyomrey
16-10-19在14:49



#2 楼

从5.2.9版本开始,如果您使用array_unique()标志,则可以使用SORT_REGULAR,如下所示:非常适合您的情况。

输出

 $a == $b 


保持但是请记住,文档指出:


Array ( [0] => Array ( [0] => abc [1] => def ) [1] => Array ( [0] => ghi [1] => jkl ) [2] => Array ( [0] => mno [1] => pql ) ) 不适用于多维数组。


评论


我猜这比公认的解决方案更快捷,更清晰!让我们为这个投票! :)嗯,在php网站上,我们可以看到它不是我想的那么快...

–安德隆
15年5月5日在10:50



奇怪的是,使用SORT_REGULAR标志对我不起作用,以删除重复的数组。

– Stefan
15年7月30日在8:28

@Stefan你是对的;它似乎没有给出正确的结果,但这可能是一个错误,因为它可与PHP 7配合使用= /

–Ja͢ck
15年7月30日在9:25

在我看来,这似乎也可行,但是其他人是否对array_unique()文档中的此注释感到不安? php.net/manual/en/…

– Arleigh Hix
16年5月2日在18:46

@Jack您说得对,这是自PHP 5.6.23:eval.in/645675起的错误,但已从PHP 7.0.8:eval.in/645676起被修复。

–扎克·莫里斯(Zack Morris)
16-09-21在1:40

#3 楼

我遇到了类似的问题,但是我找到了100%可行的解决方案。

<?php
    function super_unique($array,$key)
    {
       $temp_array = [];
       foreach ($array as &$v) {
           if (!isset($temp_array[$v[$key]]))
           $temp_array[$v[$key]] =& $v;
       }
       $array = array_values($temp_array);
       return $array;

    }


$arr="";
$arr[0]['id']=0;
$arr[0]['titel']="ABC";
$arr[1]['id']=1;
$arr[1]['titel']="DEF";
$arr[2]['id']=2;
$arr[2]['titel']="ABC";
$arr[3]['id']=3;
$arr[3]['titel']="XYZ";

echo "<pre>";
print_r($arr);
echo "unique*********************<br/>";
print_r(super_unique($arr,'titel'));

?>


评论


这回答了一个不同的问题。看到这里:stackoverflow.com/questions/4585208/…

– OIS
13年2月8日在23:28

功能强大!并且如果您正在处理对象:if(!isset($ array-> $ v-> $ key))$ array [$ v-> $ key] =&$ v;

– Playnox
16 Mar 17 '16 at 19:06



#4 楼

另一种方式。也将保留密钥。

function array_unique_multidimensional($input)
{
    $serialized = array_map('serialize', $input);
    $unique = array_unique($serialized);
    return array_intersect_key($input, $unique);
}


评论


对于大型阵列,此方法通常比接受的答案至少快50%。

–洛里恩·布鲁恩
5月13日20:28

#5 楼

用户对array_unique()文档的评论对此有很多解决方案。这是其中之一:


rbnsn点com上的kenrbnsn
2005年9月27日12:09

另一个Array_Unique用于多维数组。我仅在二维数组上进行了测试,但是可能可以推广使用它,或者可以使用递归。

该函数使用serialize,array_unique和unserialize函数来完成工作。 。


function multi_unique($array) {
    foreach ($array as $k=>$na)
        $new[$k] = serialize($na);
    $uniq = array_unique($new);
    foreach($uniq as $k=>$ser)
        $new1[$k] = unserialize($ser);
    return ($new1);
}



这是从http://ca3.php.net/manual/zh/function.array-unique.php#57202。

#6 楼

Array
(
    [0] => Array
        (
            [id] => 1
            [name] => john
        )

    [1] => Array
        (
            [id] => 2
            [name] => smith
        )

    [2] => Array
        (
            [id] => 3
            [name] => john
        )

    [3] => Array
        (
            [id] => 4
            [name] => robert
        )

)

$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);


这将从数组中删除重复的名称。按键唯一

评论


确保$ array的键从“ 0”开始。如果$ array是先前数组操作的结果,则$ array的键可能以另一个数字开头。使用array_values将键重置回“ 0”

–stevevance
5月28日18:19



#7 楼

如果“删除重复项”的意思是“删除重复项,但在那儿放一个”,一个解决方案可能是先在“标识符列”上应用array_unique(...),然后再在原始数组中删除从该列中删除的所有键。数组:

$array = [
    [
        'id' => '123',
        'foo' => 'aaa',
        'bar' => 'bbb'
    ],
    [
        'id' => '123',
        'foo' => 'ccc',
        'bar' => 'ddd'
    ],
    [
        'id' => '567',
        'foo' => 'eee',
        'bar' => 'fff'
    ]
];

$ids = array_column($array, 'id');
$ids = array_unique($ids);
$array = array_filter($array, function ($key, $value) use ($ids) {
    return in_array($value, array_keys($ids));
}, ARRAY_FILTER_USE_BOTH);


结果是:

Array
(
    [0] => Array
        (
            [id] => 123
            [foo] => aaa
            [bar] => bbb
        )

    [2] => Array
        (
            [id] => 567
            [foo] => eee
            [bar] => fff
        )

)


#8 楼

简单的解决方案:

array_unique($array, SORT_REGULAR)


#9 楼

只需将SORT_REGULAR选项用作第二个参数即可。

$uniqueArray = array_unique($array, SORT_REGULAR);


评论


SORT_REGULAR仅在PHP 7中有效,因为PHP 5有一个错误(尽管@ r3wt根据文档是正确的),请在答案中查看我的评论,以获取可运行的示例stackoverflow.com/questions/307674/…

–扎克·莫里斯(Zack Morris)
16-09-21在1:42

你为什么要添加这个?与此答案相同,它比您的答案大一年以上:stackoverflow.com/a/18373723/870729

–random_user_name
17年4月14日在20:27

#10 楼

如果您需要消除特定键(例如mysqli id)上的重复项,请使用简单的功能

function search_array_compact($data,$key){
    $compact = [];
    foreach($data as $row){
        if(!in_array($row[$key],$compact)){
            $compact[] = $row;
        }
    }
    return $compact;
}


加分点
您可以传递键的数组并添加一个外部foreach,但每增加一个键,速度将降低2倍。

#11 楼

唯一化多维数组的一种非常简单且合乎逻辑的方法如下:

如果您具有这样的数组:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value1
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value4
        )
)


使用foreach解决此问题的方法:

foreach($array as $k=>$v){
    $unique=array_unique($v);
    $array[$k]=$unique;
}


它会为您提供以下结果:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
            [4] => Value4
        )
)


,如果您想重新排列键的顺序,

foreach($array as $k=>$v){
    $unique= array_values(array_unique($v));
    $array[$k]=$unique;
}


此操作将为您安排键值,如下所示:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
            [3] => Value4
        )
)


我希望这会清除一切。

#12 楼

如果具有这样的数组:

(用户是数组的名称)

Array=>
 [0] => (array)
   'user' => 'john'
   'age' => '23'
 [1] => (array)
  'user' => 'jane'
  'age' => '20'
 [2]=> (array)
  'user' => 'john'
  'age' => '23'


,并且您要删除重复项。 .then:

$serialized = array();
for ($i=0; $i < sizeof($users); $i++) { 
  $test = in_array($users['user'], $serialized);
    if ($test == false) {
      $serialized[] = $users['user'];
    }
 }


可以解决:P

#13 楼

一个易于阅读的解决方案,可能不是最有效的解决方案:

function arrayUnique($myArray){
    if(!is_array($myArray))
        return $myArray;

    foreach ($myArray as &$myvalue){
        $myvalue=serialize($myvalue);
    }

    $myArray=array_unique($myArray);

    foreach ($myArray as &$myvalue){
        $myvalue=unserialize($myvalue);
    }

    return $myArray;

} 


#14 楼

正如人们所说的array_unique()非常慢,这是我用于一级多维数组的代码段。

$serialized_array = array_map("serialize", $input);

foreach ($serialized_array as $key => $val) {
     $result[$val] = true;
}

$output = array_map("unserialize", (array_keys($result)));


参考第一个用户在php中对array_unique()功能页的注释。净

评论


Anuj,能否请您编辑答案?有一个错误。它应该以$ output = array_map('unserialize',array_keys($ result))结尾;

–keyboardSmasher
15年5月16日在15:18

@keyboardSmasher感谢您的输入。我进行了更改,现在可以使用了。 :)

– Anuj
15年5月22日在13:07

#15 楼

很多人问我如何制作独特的多维数组。我已从您的评论中获取参考,这对我有帮助。首先,感谢@jeromegamez @daveilers为您提供的解决方案。但是每次我给出答案时,他们都会问我“序列化”和“反序列化”是如何工作的。这就是为什么我想与您分享其原因,以便它将帮助更多的人理解其背后的概念。

我正在解释为什么在步骤中同时使用'serialize'和'unserialize':

步骤1:将多维数组转换为一维数组

要将多维数组转换为一维数组,请首先生成数组内部所有元素(包括嵌套数组)的字节流表示形式。 serialize()函数可以生成值的字节流表示形式。要生成所有元素的字节流表示形式,请在array_map()函数内部调用serialize()函数作为回调函数。无论多维数组有多少层,结果都是一维数组。

步骤2:使值唯一

要使此一维数组唯一,请使用array_unique()函数。

步骤3:将其还原为多维数组

尽管数组现在是唯一的,但其值看起来像字节流表示形式。要将其还原为多维数组,请使用unserialize()函数。

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));


再次感谢所有这些。

#16 楼

序列化和唯一的替代方法




$test = [
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
];

$result = array_reduce(
    $test,
    function($carry,$item){
        if(!in_array($item,$carry)) {
            array_push($carry,$item);
        }
        return $carry;
    },
    []
);

var_dump($result);

/*
 php unique.php
array(3) {
    [0] =>
        array(2) {
            [0] =>
                string(3) "abc"
            [1] =>
                string(3) "def"
        }
    [1] =>
        array(2) {
            [0] =>
                string(3) "ghi"
            [1] =>
                string(3) "jkl"
        }
    [2] =>
        array(2) {
              [0] =>
                  string(3) "mno"
              [1] =>
                  string(3) "pql"
        }
}


* /

#17 楼

如果您有一个像这样的数组

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => b
),
[3] => array
(
    [subject] => d
    [object] => c
),
[4] => array
(
    [subject] => c
    [object] => a
),
[5] => array
(
    [subject] => c
    [object] => d
)
)


,而您想要得到这样的数组:

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => c
)
)




data = array
(
[0] => array
(
    [subject] => d
    [object] => b
),
[1] => array
(
    [subject] => c
    [object] => a
),
[2] => array
(
    [subject] => c
    [object] => d
)
)


以下代码可以提供帮助

    $data1 = array();
    $data1 = $data;
    for($q=0;$q<count($data);$q++)
    {
            for($p=0;$p<count($data1);$p++)
            {
                    if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"]))
                    {
                            $data1[$p]["subject"] = $data[$q]["subject"];
                            $data1[$p]["object"] = $data[$q]["object"];
                    }
            }
    }
    $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1))));
    $data = $data1;


#18 楼

我已经考虑了这个问题,并确定最佳解决方案应遵循两个规则。


为了实现可伸缩性,请就地修改数组。不能复制到新数组中。
为了提高性能,每次比较都应该只进行一次

考虑到这一点,并考虑到所有PHP的怪癖,下面是我想出的解决方案。与其他答案不同,它具有根据所需键删除元素的功能。输入数组应该是数字键。

$count_array = count($input);
for ($i = 0; $i < $count_array; $i++) {
    if (isset($input[$i])) {
        for ($j = $i+1; $j < $count_array; $j++) {
            if (isset($input[$j])) {
                //this is where you do your comparison for dupes
                if ($input[$i]['checksum'] == $input[$j]['checksum']) {
                    unset($input[$j]);
                }
            }
        }
    }
}


唯一的缺点是,迭代完成后,键的顺序不正确。如果您随后仅使用foreach循环,那么这不是问题,但是如果您需要使用for循环,则可以在上面的后面加上$input = array_values($input);来对键进行重新编号。

#19 楼

根据标记为正确的答案,添加我的答案。添加了小代码只是为了重置索引-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));


#20 楼

我已经尝试过删除重复项。
$array = array_map("unserialize", array_unique(array_map("serialize", $array)));