nesneler için array_unique?


Yanıtlar:


98

Peki, array_unique()elemanların dize değerini karşılaştırır:

Not : İki öğenin eşit olduğu kabul edilir, ancak ve ancak, (string) $elem1 === (string) $elem2örneğin dizgi gösterimi aynı olduğunda, ilk öğe kullanılacaktır.

Bu nedenle, __toString()yöntemi sınıfınızda uyguladığınızdan ve eşit roller için aynı değeri çıkardığından emin olun , örn.

class Role {
    private $name;

    //.....

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

}

Bu, aynı ada sahiplerse iki rolü eşit kabul eder.


2
@Jacob çünkü ne array_uniquede __toString()hiçbir şeyi karşılaştırmayın. __toString()bir dize bağlamında kullanıldığında bir nesne örneğinin nasıl davranması gerektiğini tanımlar ve array_uniqueyinelenen değerleri kaldırılmış girdi dizisini döndürür. Bunun için dahili olarak karşılaştırma kullanır .
Gordon

1
@Jacob Relkin: Karşılaştırıcı değil. Nesnenin dizgi temsilidir. Sanırım bunu herhangi bir türü, nesneyi vb. Bir dizeye dönüştürebildiğiniz için kullanıyorlar. Ancak bir nesne üzerindeki dize yönteminin kendisi yalnızca bu işlev tarafından kullanılmaz. Örneğin yöntemi echo $objectde kullanır __toString.
Felix Kling

3
Ekleme __toString()tüm nesnelere yöntemleri çok daha ağrılı sonra sadece bir ekleme olduğu SORT_REGULAR, array_unique Matthieu Napoli onun cevabını görmek için bayrak. Ayrıca bir __toString()yöntemin daha sonra nesne karşılaştırması için kullanılan birçok başka kullanım durumu vardır, bu nedenle bu mümkün olmayabilir bile.
çevirin

156

array_uniqueaşağıdakileri kullanarak bir dizi nesneyle çalışır 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));

Yazdırılacak:

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

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

Burada nasıl çalıştığını görün: http://3v4l.org/VvonH#v529

Uyarı : "==" karşılaştırmasını kullanır, katı karşılaştırmayı değil ("===").

Bu nedenle, bir dizi nesnenin içindeki kopyaları kaldırmak istiyorsanız, nesne kimliğini (örnek) değil, her nesne özelliğini karşılaştıracağına dikkat edin.


12
Bu cevap, kabul edilen cevaptan çok daha iyidir. Bununla birlikte, örnek değer ( ==) veya kimlik ( ===) karşılaştırması arasındaki farkı (farkı göstermek için $bam->prop = 'test2';olmalıdır 'test1') göstermez. Örnek için codepad.viper-7.com/8NxWhG adresine bakın .
çevirin

@vishal resmi belgelere bir göz atın: php.net/manual/en/function.array-unique.php
Matthieu Napoli

1
beni çok kurtardın kardeşim, TnQ: *
Saman Sattari

1
Kabul edilen cevap olmalı. Ayrıca bu, __toString () kullanmaktan çok daha hızlıdır. Karşılaştırma sonucu için bkz . Sandbox.onlinephpfunctions.com/code/… .
LucaM

1
Array_unique () ile nesneleri karşılaştırırken dikkatli olun, işlev derin bir karşılaştırma uygulayacaktır, bu çok fazla özyineleme içeriyorsa sunucunuzun çökmesine neden olabilir — Size Doctrine varlıklarına bakıyorum. Nesnenizi neyin benzersiz kıldığını daha iyi belirleyin ve nesnelerinizi bununla indeksleyin. Örneğin, nesnelerinizin bir dize tanımlayıcısı varsa, bu tanımlayıcıyı anahtar olarak kullanarak bir dizi oluşturun.
olvlvl

31

PHP 5'te nesneleri karşılaştırmanınin_array() doğası bunu yapmamıza izin verdiği için bu cevap kullanılır . Bu nesne karşılaştırma davranışından yararlanmak, dizinin yalnızca nesneleri içermesini gerektirir , ancak burada durum böyle görünüyor.

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

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

var_dump($final);

1
Güzel çalışıyor, diğerinden daha hızlı olabilir (gerçekten bilmiyorum) ama seninkini kullanacağım çünkü bunun için fazladan bir işlev yapmak zorunda
değilim

Nesneleri karşılaştırırken, aynı miktarda alana sahip olmaları ve aynı doğru kabul edilmeleri için aynı anahtar / değer çiftleri olmaları gerekir mi?
anladığım

1
in_array$strictparametreyi kullanmalısınız ! Başka bir deyişle, "===" yerine "==" kullanarak nesneleri karşılaştırabilirsiniz. Daha fazla bilgi için: fr2.php.net/manual/fr/function.in-array.php
Matthieu Napoli

1
Değil sıkı parametresini kullanarak burada bilinçli bir seçim oldu. Bir nesnenin mutlaka aynı örneğini değil, "eşit" nesneleri bulmak istedim . Bu, yanıtta belirtilen bağlantıda açıklanmaktadır, " Karşılaştırma operatörü (==) kullanılırken, nesne değişkenleri basit bir şekilde karşılaştırılır, yani: Aynı özniteliklere ve değerlere sahiplerse iki nesne örneği eşittir, ve aynı sınıfın örnekleridir. "
2014

Tıkır tıkır çalışıyor! Çok teşekkürler
gronaz

17

Bir dizideki çoğaltılmış nesneleri kaldırmanın bir yolu:

<?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);

Bu benim için en iyi çözüm! Bu çözümü web sitesi arama motorum için kullanıyorum (bir veritabanından 2 sorgu sonucunu birleştirme). Önce tüm arama terimleri için sonuçlarım var ve bunları bazı arama terimlerinin sonuçlarıyla birleştiriyorum. Bu çözümle önce en önemli sonuçları aldım, benzersiz diğer çözümlerle ekledim ..
Finduilas

11

Ayrıca önce serileştirebilirsiniz:

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

PHP 5.2.9'dan itibaren isteğe bağlı olarak kullanabilirsiniz sort_flag SORT_REGULAR:

$unique = array_unique( $array, SORT_REGULAR );

9

Nesneleri belirli bir özniteliğe göre filtrelemek istiyorsanız, dizi_filtresi işlevini de kullanabilirsiniz:

//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

Buradan: http://php.net/manual/en/function.array-unique.php#75307

Bu, nesneler ve dizilerle de çalışır.

<?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

Dizine alınmış bir nesne dizisine sahipseniz ve her nesnedeki belirli bir özelliği karşılaştırarak kopyaları kaldırmak istiyorsanız, remove_duplicate_models()aşağıdaki gibi bir işlev kullanılabilir.

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 ) );

Sonuç:

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

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

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

)

0

diziden çoğaltılmış örnekleri filtrelemeniz gerekiyorsa (yani "===" karşılaştırması) mantıklı ve hızlı bir yol ve:

  • hangi dizinin yalnızca nesneleri tuttuğundan eminsiniz
  • korunmuş anahtarlara ihtiyacın yok

dır-dir:

//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

Bu çok basit bir çözüm:

$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, öğeleri bir dizeye çevirerek ve bir karşılaştırma yaparak çalışır. Nesneleriniz benzersiz bir şekilde dizelere dönüştürülmedikçe, array_unique ile çalışmazlar.

Bunun yerine, nesneleriniz için durum bilgili bir karşılaştırma işlevi uygulayın ve işlevin daha önce gördüğü şeyleri atmak için array_filter kullanın.


Daha zarif bir çözüm bulmayı umuyordum (geri arama gerektirmeyen bir çözüm). Yine de cevabınızı takdir edin.
Emanuil Rusev

1
array_uniqueSORT_REGULAR çalışmalarıyla kullanılır, aşağıdaki cevabıma bakın.
Matthieu Napoli

-1

Bu, basit özelliklere sahip nesneleri karşılaştırmanın ve aynı zamanda benzersiz bir koleksiyon elde etme yolum:

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);

Çıktı:

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

-1

Nesneler dizisine sahipseniz ve tüm kopyaları kaldırmak için bu koleksiyonu filtrelemek istiyorsanız anonim işlevle array_filter kullanabilirsiniz:

$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;
});

Önemli:$tmp Geri arama işlevini filtrelemek için diziyi referans olarak iletmeniz gerektiğini unutmayın, aksi takdirde çalışmaz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.