array_unique对象?


Answers:


97

好吧,array_unique()比较元素的字符串值:

注意:当且仅(string) $elem1 === (string) $elem2当字符串表示相同时,将使用第一个元素,才将两个元素视为相等。

因此,请确保__toString()在您的类中实现该方法,并为相等的角色输出相同的值,例如

class Role {
    private $name;

    //.....

    public function __toString() {
        return $this->name;
    }

}

如果两个角色具有相同的名称,则将其视为相等。


2
@Jacob因为既不比较array_unique也不__toString()比较。__toString()定义在字符串上下文中使用对象实例时应如何表现,并array_unique返回除去重复值的输入数组。它只是使用了这种比较内部。
Gordon

1
@Jacob Relkin:它不是比较器。它是对象的字符串表示形式。我认为他们使用它是因为您可以将任何类型,对象等转换为字符串。但是对象上的字符串方法本身不仅由该函数使用。例如echo $object也使用该__toString方法。
Felix Kling 2010年

3
__toString()您的所有对象添加方法要比仅向SORT_REGULARarray_unique添加标志要痛苦得多,请参阅Matthieu Napoli他的回答。此外,__toString()方法还有许多其他用例用于对象比较,因此这甚至是不可能的。
2014年

154

array_unique使用SORT_REGULAR以下对象处理对象数组:

class MyClass {
    public $prop;
}

$foo = new MyClass();
$foo->prop = 'test1';

$bar = $foo;

$bam = new MyClass();
$bam->prop = 'test2';

$test = array($foo, $bar, $bam);

print_r(array_unique($test, SORT_REGULAR));

将打印:

Array (
    [0] => MyClass Object
        (
            [prop] => test1
        )

    [2] => MyClass Object
        (
            [prop] => test2
        )
)

在此处查看其运行情况:http: //3v4l.org/VvonH#v529

警告:它将使用“ ==”比较,而不是严格比较(“ ===”)。

因此,如果要删除对象数组中的重复项,请注意它将比较每个对象属性,而不是比较对象标识(实例)。


12
这个答案比接受的答案好得多。但是,该示例并未显示值(==)或身份(===)的比较之间的差异,这是因为$bam->prop = 'test2';(应该'test1'展示差异)。有关示例,请参见codepad.viper-7.com/8NxWhG
2014年


1
您为我节省了兄弟,TnQ非常多:*
Saman Sattari '16

1
应该是公认的答案。这也比使用__toString()快得多。请参阅:sandbox.onlinephpfunctions.com/code/…以获取比较结果。
LucaM

1
当心与array_unique()比较对象,该函数将进行深度比较,如果涉及过多的递归,则可能会导致服务器崩溃—我正在查看您的Doctrine实体。更好地确定是什么使您的对象具有唯一性,并使用它为您的对象建立索引。例如,如果您的对象具有字符串标识符,则以该标识符为键构建一个数组。
olvlvl

31

之所以使用此答案,是in_array()因为PHP 5中比较对象的性质允许我们这样做。利用此对象比较行为需要数组包含对象,但在这里似乎是这种情况。

$merged = array_merge($arr, $arr2);
$final  = array();

foreach ($merged as $current) {
    if ( ! in_array($current, $final)) {
        $final[] = $current;
    }
}

var_dump($final);

1
效果很好,它可能比另一个更快(真的不知道),但是我会用你的,因为我不必为此做一个额外的功能:D
Gigala 2013年

比较对象时,它们必须具有相同数量的字段,并且必须具有相同的键/值对才能被视为相同的正确对象?我正在得到的是....如果我有2个对象,其中一个具有一个额外的字段,这些对象将不被视为“相同”
ChuckKelly 2013年

1
in_array应该使用$strict参数!否则,您将使用“ ==”而不是“ ===“来比较对象。此处更多内容:fr2.php.net/manual/fr/function.in-array.php
Matthieu Napoli

1
此处选择严格参数是一个有意的选择。我想找到“相等”的对象,而不一定对象的相同实例。答案中提到的链接对此进行了解释,该链接说:“使用比较运算符(==)时,以简单的方式比较对象变量,即:如果两个对象实例具有相同的属性和值,则它们相等;并且是同一类的实例。
萨拉特(Salathe)2014年

奇迹般有效!非常感谢
gronaz

16

这是一种删除数组中重复对象的方法:

<?php
// Here is the array that you want to clean of duplicate elements.
$array = getLotsOfObjects();

// Create a temporary array that will not contain any duplicate elements
$new = array();

// Loop through all elements. serialize() is a string that will contain all properties
// of the object and thus two objects with the same contents will have the same
// serialized string. When a new element is added to the $new array that has the same
// serialized value as the current one, then the old value will be overridden.
foreach($array as $value) {
    $new[serialize($value)] = $value;
}

// Now $array contains all objects just once with their serialized version as string.
// We don't care about the serialized version and just extract the values.
$array = array_values($new);

这对我来说是最好的解决方案!我正在将这种解决方案用于我的网站搜索引擎(合并来自数据库的2个查询结果)。首先,我拥有所有搜索项的结果,然后将它们与某些搜索项的结果合并。使用此解决方案,我首先获得了最重要的结果,再加上其他独特的解决方案
。.– Finduilas

11

您还可以先序列化:

$unique = array_map( 'unserialize', array_unique( array_map( 'serialize', $array ) ) );

从PHP 5.2.9开始,您可以仅使用optional sort_flag SORT_REGULAR

$unique = array_unique( $array, SORT_REGULAR );

9

如果要基于特定属性过滤对象,也可以使用它们array_filter函数:

//filter duplicate objects
$collection = array_filter($collection, function($obj)
{
    static $idList = array();
    if(in_array($obj->getId(),$idList)) {
        return false;
    }
    $idList []= $obj->getId();
    return true;
});

6

从这里:http : //php.net/manual/zh/function.array-unique.php#75307

这个也可以处理对象和数组。

<?php
function my_array_unique($array, $keep_key_assoc = false)
{
    $duplicate_keys = array();
    $tmp         = array();       

    foreach ($array as $key=>$val)
    {
        // convert objects to arrays, in_array() does not support objects
        if (is_object($val))
            $val = (array)$val;

        if (!in_array($val, $tmp))
            $tmp[] = $val;
        else
            $duplicate_keys[] = $key;
    }

    foreach ($duplicate_keys as $key)
        unset($array[$key]);

    return $keep_key_assoc ? $array : array_values($array);
}
?>

2

如果您有一个带索引的对象数组,并且想通过比较每个对象中的特定属性来删除重复项,remove_duplicate_models()则可以使用下面的函数。

class Car {
    private $model;

    public function __construct( $model ) {
        $this->model = $model;
    }

    public function get_model() {
        return $this->model;
    }
}

$cars = [
    new Car('Mustang'),
    new Car('F-150'),
    new Car('Mustang'),
    new Car('Taurus'),
];

function remove_duplicate_models( $cars ) {
    $models = array_map( function( $car ) {
        return $car->get_model();
    }, $cars );

    $unique_models = array_unique( $models );

    return array_values( array_intersect_key( $cars, $unique_models ) );
}

print_r( remove_duplicate_models( $cars ) );

结果是:

Array
(
    [0] => Car Object
        (
            [model:Car:private] => Mustang
        )

    [1] => Car Object
        (
            [model:Car:private] => F-150
        )

    [2] => Car Object
        (
            [model:Car:private] => Taurus
        )

)

0

如果您需要从数组中过滤出重复的实例(即“ ===比较”),则采用一种明智而又快速的方法:

  • 您确定什么数组仅包含对象
  • 您不需要保留密钥

是:

//sample data
$o1 = new stdClass;
$o2 = new stdClass;
$arr = [$o1,$o1,$o2];

//algorithm
$unique = [];
foreach($arr as $o){
  $unique[spl_object_hash($o)]=$o;
}
$unique = array_values($unique);//optional - use if you want integer keys on output

0

这是非常简单的解决方案:

$ids = array();

foreach ($relate->posts as $key => $value) {
  if (!empty($ids[$value->ID])) { unset($relate->posts[$key]); }
  else{ $ids[$value->ID] = 1; }
}

-1

array_unique通过将元素转换为字符串并进行比较来工作。除非您的对象唯一地转换为字符串,否则它们将无法与array_unique一起使用。

相反,为您的对象实现一个有状态的比较函数,并使用array_filter抛出该函数已经看到的东西。


我希望有一个更优雅的解决方案(不需要回调)。不过,感谢您的回答。
Emanuil Rusev 2011年

1
array_unique与SORT_REGULAR一起使用时,请参见下面的答案。
Matthieu Napoli

-1

这是我比较具有简单属性的对象的方法,同时又收到一个唯一的集合:

class Role {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

$roles = [
    new Role('foo'),
    new Role('bar'),
    new Role('foo'),
    new Role('bar'),
    new Role('foo'),
    new Role('bar'),
];

$roles = array_map(function (Role $role) {
    return ['key' => $role->getName(), 'val' => $role];
}, $roles);

$roles = array_column($roles, 'val', 'key');

var_dump($roles);

将输出:

array (size=2)
  'foo' => 
    object(Role)[1165]
      private 'name' => string 'foo' (length=3)
  'bar' => 
    object(Role)[1166]
      private 'name' => string 'bar' (length=3)

-1

如果您有对象数组,并且想要过滤此集合以删除所有重复项,则可以将array_filter与匿名函数一起使用:

$myArrayOfObjects = $myCustomService->getArrayOfObjects();

// This is temporary array
$tmp = [];
$arrayWithoutDuplicates = array_filter($myArrayOfObjects, function ($object) use (&$tmp) {
    if (!in_array($object->getUniqueValue(), $tmp)) {
        $tmp[] = $object->getUniqueValue();
        return true;
    }
    return false;
});

重要提示:请记住,必须将$tmp数组作为对过滤器回调函数的引用进行传递,否则它将不起作用

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.