合并包含对象的两个数组并删除重复值

82

我需要将两个对象数组合并为一个,并删除重复的email值。

我该怎么做?

以下是我的示例数组:

$array1 = [
    (object) ["email" => "gffggfg"],
    (object) ["email" => "wefwef@test.it"],
    (object) ["email" => "wefewf"],
];
$array2 = [
    (object) ["email" => "gffggfg@test.it"],
    (object) ["email" => "wefwef"],
    (object) ["email" => "wefewf"],
];

我的预期结果是:

[
   (object) ['email' => 'gffggfg'],
   (object) ['email' => 'wefwef@test.it'],
   (object) ['email' => 'wefewf'],
   (object) ['email' => 'gffggfg@test.it'],
   (object) ['email' => 'wefwef'],
]
8个回答

210

你可以将 array_merge() 函数与 array_unique() 函数结合使用(它们的标题都相当自说明)

$array = array_unique (array_merge ($array1, $array2));

据我所见,array_merge() 似乎不会计算重复项,因此在我的情况下 array_unique() 是否已被弃用? - itsme
1
array_merge() 不会添加重复的键,但是当您有不同键的重复值时,它会将它们添加到数组中。 - Jeroen
1
应该添加对SORT_REGULAR和其他选项的提及,以避免在类型转换时出现错误。 - Brandon Elliott
6
注意:array_unique 会保留键名,所以对于数字索引数组,如果您需要顺序键名,可以通过使用 array_values 函数来快速重新分配键名。 - highvolt
2
尽管这个简洁的答案获得了大量的赞同和绿色的勾选标志,但是根据提问者的样本数据,它是可以被证明是错误的。 - mickmackusa

13

如果我正确理解了问题:

 $a1 = Array(1,2,3,4);
 $a2 = Array(4,5,6,7);
 $array =  array_diff(array_merge($a1,$a2),array_intersect($a1,$a2));
 print_r($array);

返回

Array
(
[0] => 1
[1] => 2
[2] => 3
[5] => 5
[6] => 6
[7] => 7
)

抱歉,我忘记了我有多级数组而不是简单的数组。 - itsme
这个未解释的答案不仅不能处理提问者的数据,即使可以,也不会很高效,因为它进行了基于值的比较。在PHP中,基于键的比较总是更快执行。 - mickmackusa

6

我一直在对所有我能想到的方法进行基准测试,其中包括堆叠许多由10-20个字符串元素组成的数组,从而得到一个包含所有唯一字符串的数组。这对于仅堆叠2个数组应该是大致相同的。

我发现最快的方法是我尝试过的最简单的东西。

$uniques = [];
foreach($manyArrays as $arr ) {
  $uniques = array_unique(array_merge($uniques, $arr));
}

我曾经认为这个方法“太幼稚了,不能工作”,因为它每次迭代都必须对唯一数组进行排序。然而,这比任何其他方法都要快。在 PHP 7.3 中,测试了许多包含 10-20 个字符串的元素的 manyArrays,共计 500,000 个元素。

紧随其后的是第二种方法,速度大约慢了 10%。

$uniques = [];
foreach($manyArrays as $arr ) {
  foreach($arr as $v) {
    if( !in_array($v, $uniques, false) ) {
      $uniques[] = $v;
    }
  }
}

第二种方法在某些情况下可能更好,因为它支持 in_array() 函数的 'strict' 参数进行严格类型检查。但如果设置为 true,则第二个选项比第一个选项要慢得多(大约 40%)。第一个选项不支持严格类型检查。

在这个任务的上下文中,你是如何填充$manyArrays的? - mickmackusa

1
因为对象数组中的`email`属性包含非数字值,所以可以临时分配第一级键(使用`array_column()`)然后使用联合运算符将两个数组合并(这是一个无需函数的操作)。
如果临时键干扰了下一个流程,可以使用`array_values()`重新索引数组。
代码: (演示)
var_export(
    array_values(
        array_column($array1, null, 'email')
        + array_column($array2, null, 'email')
    )
);

输出:

array (
  0 => 
  (object) array(
     'email' => 'gffggfg',
  ),
  1 => 
  (object) array(
     'email' => 'wefwef@test.it',
  ),
  2 => 
  (object) array(
     'email' => 'wefewf',
  ),
  3 => 
  (object) array(
     'email' => 'gffggfg@test.it',
  ),
  4 => 
  (object) array(
     'email' => 'wefwef',
  ),
)

“合并并保留唯一对象”也可以使用特殊标志来实现。
代码:(演示)
var_export(
    array_unique(
        array_merge($array1, $array2),
        SORT_REGULAR
    )
);
// same result as other snippet

1
更快的解决方案:
function concatArrays($arrays){
    $buf = [];
    foreach($arrays as $arr){
        foreach($arr as $v){
            $buf[$v] = true;
        }
    }
    return array_keys($buf);
}


$array = concatArrays([$array1, $array2]);

4
嵌套 foreach 循环为什么比内置函数更快?你有基准测试结果吗? - mcmurphy
这是证明此答案与提问者提供的数据不兼容的链接:https://3v4l.org/dp6tt - mickmackusa

0
非常古老的帖子,但是... OP的数组包含对象。 如果我是OP,我会声明一个类,在构造函数中接收子数组,并使用__toString()函数返回电子邮件。 如果OP将他的对象变成该类的实例,则array_unique在比较时应调用__toString()。

你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

0
<?php
   $array1 = array("yellow", "red", "green", "orange", "purple");
   $array2 = array("pink", "brown", "green", "orange", "red");
   $array = array_unique(array_merge($array1, $array2));
   print_r($array);
?>
 
Array
(
    [0] => yellow
    [1] => red
    [2] => green
    [3] => orange
    [4] => purple
    [5] => pink
    [6] => brown
)

-1
有点晚了的回答,但我刚发现数组联合运算符+非常好用(在第三部分这里找到)。
$array1 + $array2 = $array //if duplicate found, the value in $array1 will be considered ($array2 value for array_merge, if keys clearly specified)

不是一个好的选择!如果数组键相同但值不同,则会得到错误的数据,例如:$array1 = Array([0] => 0,[1] => 1,[2] => 2) $array2 = Array([0] => 3) $array1 + $array2 = Array([0] => 0,[1] => 1,[2] => 2)更好的选择是array_unique(array_merge($array1,$array2))= Array([0] => 0,[1] => 1,[2] => 2,[3] => 3) - Pran
这不会导致数组值的联合,请参见php.net - Aurovrata

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