Uwaga : Dwa elementy są uważane za równe wtedy i tylko wtedy, (string) $elem1 === (string) $elem2gdy np. Gdy reprezentacja łańcuchowa jest taka sama, zostanie użyty pierwszy element.
Dlatego upewnij się, że zaimplementowałeś __toString()metodę w swojej klasie i że daje ona taką samą wartość dla równych ról, np
@Jacob, ponieważ ani array_uniquenie __toString()porównuj niczego. __toString()definiuje, jak instancja obiektu powinna zachowywać się, gdy jest używana w kontekście ciągów i array_uniquezwraca tablicę wejściową z usuniętymi zduplikowanymi wartościami. Po prostu używa porównania do tego wewnętrznie.
Gordon
1
@Jacob Relkin: To nie jest komparator. Jest to ciąg znaków reprezentujący obiekt. Myślę, że używają tego, ponieważ można przekonwertować dowolny typ, obiekt itp. Na ciąg. Ale sama metoda napisów na obiekcie jest używana nie tylko przez tę funkcję. Np. echo $objectRównież używa tej __toStringmetody.
Felix Kling
3
Dodawanie __toString()metod do wszystkich obiektów jest znacznie bardziej bolesne niż po prostu dodawanie SORT_REGULARflagi do array_unique, zobacz odpowiedź Matthieu Napoli. Poza tym __toString()metoda ma wiele innych przypadków użycia używanych do porównywania obiektów, więc może to nawet nie być możliwe.
Flip
156
array_uniquedziała z tablicą obiektów używając SORT_REGULAR:
Ta odpowiedź jest znacznie lepsza niż zaakceptowana odpowiedź. Jednak przykład nie pokazuje różnicy między porównaniem wartości ( ==) lub tożsamością ( ===) z powodu $bam->prop = 'test2';(powinno być 'test1'pokazanie różnicy). Przykład można znaleźć pod adresem codepad.viper-7.com/8NxWhG .
Powinna być zaakceptowana odpowiedź. Również to dużo szybciej niż przy użyciu __toString (). Zobacz: sandbox.onlinephpfunctions.com/code/ ... aby zobaczyć wynik porównania.
LucaM,
1
Uważaj, porównując obiekty za pomocą array_unique (), funkcja zastosuje głębokie porównanie, które może spowodować awarię serwera, jeśli wymaga zbyt dużej rekurencji - patrzę na ciebie, encje Doctrine. Lepiej zidentyfikuj, co sprawia, że Twój obiekt jest unikalny i zindeksuj nim swoje obiekty. Na przykład, jeśli obiekty mają identyfikator w postaci łańcucha, utwórz tablicę z tym identyfikatorem jako klucz.
olvlvl
31
Ta odpowiedź jest używana, in_array()ponieważ natura porównywania obiektów w PHP 5 pozwala nam to zrobić. Korzystanie z tego zachowania polegającego na porównywaniu obiektów wymaga, aby tablica zawierała tylko obiekty, ale wydaje się, że tak jest w tym przypadku.
Działa dobrze, może być szybszy niż ten drugi (nie wiem), ale
użyję
Porównując obiekty, muszą one mieć taką samą liczbę pól i muszą być identycznymi parami klucz / wartość, aby można je było uznać za takie same, prawda? to, do czego zmierzam, to .... jeśli mam 2 obiekty i jeden z nich ma jedno dodatkowe pole, czy te obiekty nie będą uważane za „takie same”
Nieużywanie ścisłego parametru było tutaj celowym wyborem. Chciałem znaleźć „równe” obiekty, niekoniecznie tę samą instancję obiektu. Jest to wyjaśnione w odsyłaczu wymienionym w odpowiedzi, który mówi: „ Używając operatora porównania (==), zmienne obiektów są porównywane w prosty sposób, a mianowicie: Dwie instancje obiektów są równe, jeśli mają te same atrybuty i wartości, i są przykładami tej samej klasy. ”
salathe
Działa jak marzenie!
Wielkie
17
Oto sposób na usunięcie zduplikowanych obiektów z tablicy:
<?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($arrayas$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);
To dla mnie najlepsze rozwiązanie! Używam tego rozwiązania do wyszukiwania mojej witryny internetowej (scalanie 2 wyników zapytań z bazy danych). Najpierw mam wyniki wszystkich terminów wyszukiwania i łączę je z wynikami niektórych terminów wyszukiwania. Dzięki temu rozwiązaniu mam najważniejsze wyniki jako pierwsze, dodane przez inne unikalne rozwiązania ..
Jeśli masz indeksowaną tablicę obiektów i chcesz usunąć duplikaty, porównując określoną właściwość w każdym obiekcie, remove_duplicate_models()możesz użyć funkcji podobnej do poniższej.
array_unique działa poprzez rzutowanie elementów na łańcuch i wykonanie porównania. O ile twoje obiekty nie są jednoznacznie rzutowane na łańcuchy, to nie będą działać z array_unique.
Zamiast tego zaimplementuj stanową funkcję porównującą dla swoich obiektów i użyj array_filter, aby wyrzucić rzeczy, które funkcja już widziała.
Odpowiedzi:
Cóż,
array_unique()
porównuje wartości ciągów elementów:Dlatego upewnij się, że zaimplementowałeś
__toString()
metodę w swojej klasie i że daje ona taką samą wartość dla równych ról, npclass Role { private $name; //..... public function __toString() { return $this->name; } }
To uznałoby dwie role za równe, gdyby miały taką samą nazwę.
źródło
array_unique
nie__toString()
porównuj niczego.__toString()
definiuje, jak instancja obiektu powinna zachowywać się, gdy jest używana w kontekście ciągów iarray_unique
zwraca tablicę wejściową z usuniętymi zduplikowanymi wartościami. Po prostu używa porównania do tego wewnętrznie.echo $object
Również używa tej__toString
metody.__toString()
metod do wszystkich obiektów jest znacznie bardziej bolesne niż po prostu dodawanieSORT_REGULAR
flagi do array_unique, zobacz odpowiedź Matthieu Napoli. Poza tym__toString()
metoda ma wiele innych przypadków użycia używanych do porównywania obiektów, więc może to nawet nie być możliwe.array_unique
działa z tablicą obiektów używającSORT_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));
Wydrukuje:
Array ( [0] => MyClass Object ( [prop] => test1 ) [2] => MyClass Object ( [prop] => test2 ) )
Zobacz to w akcji tutaj: http://3v4l.org/VvonH#v529
Ostrzeżenie : użyje porównania „==”, a nie ścisłego porównania („===”).
Więc jeśli chcesz usunąć duplikaty wewnątrz tablicy obiektów, uważaj, że porówna on właściwości każdego obiektu, a nie jego tożsamość (instancję).
źródło
==
) lub tożsamością (===
) z powodu$bam->prop = 'test2';
(powinno być'test1'
pokazanie różnicy). Przykład można znaleźć pod adresem codepad.viper-7.com/8NxWhG .Ta odpowiedź jest używana,
in_array()
ponieważ natura porównywania obiektów w PHP 5 pozwala nam to zrobić. Korzystanie z tego zachowania polegającego na porównywaniu obiektów wymaga, aby tablica zawierała tylko obiekty, ale wydaje się, że tak jest w tym przypadku.$merged = array_merge($arr, $arr2); $final = array(); foreach ($merged as $current) { if ( ! in_array($current, $final)) { $final[] = $current; } } var_dump($final);
źródło
in_array
powinien użyć$strict
parametru! W przeciwnym razie porównujesz obiekty za pomocą „==” zamiast „===”. Więcej tutaj: fr2.php.net/manual/fr/function.in-array.phpOto sposób na usunięcie zduplikowanych obiektów z tablicy:
<?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);
źródło
Możesz również serializować najpierw:
$unique = array_map( 'unserialize', array_unique( array_map( 'serialize', $array ) ) );
Od PHP 5.2.9 możesz po prostu użyć opcjonalnego
sort_flag SORT_REGULAR
:$unique = array_unique( $array, SORT_REGULAR );
źródło
Możesz również użyć ich funkcji array_filter, jeśli chcesz filtrować obiekty na podstawie określonego atrybutu:
//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; });
źródło
Stąd: http://php.net/manual/en/function.array-unique.php#75307
Ten działałby również z obiektami i tablicami.
<?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); } ?>
źródło
Jeśli masz indeksowaną tablicę obiektów i chcesz usunąć duplikaty, porównując określoną właściwość w każdym obiekcie,
remove_duplicate_models()
możesz użyć funkcji podobnej do poniższej.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 ) );
Wynik to:
Array ( [0] => Car Object ( [model:Car:private] => Mustang ) [1] => Car Object ( [model:Car:private] => F-150 ) [2] => Car Object ( [model:Car:private] => Taurus ) )
źródło
rozsądny i szybki sposób, jeśli chcesz odfiltrować zduplikowane instancje (np. porównanie „===”) z tablicy i:
jest:
//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
źródło
To bardzo proste rozwiązanie:
$ids = array(); foreach ($relate->posts as $key => $value) { if (!empty($ids[$value->ID])) { unset($relate->posts[$key]); } else{ $ids[$value->ID] = 1; } }
źródło
array_unique działa poprzez rzutowanie elementów na łańcuch i wykonanie porównania. O ile twoje obiekty nie są jednoznacznie rzutowane na łańcuchy, to nie będą działać z array_unique.
Zamiast tego zaimplementuj stanową funkcję porównującą dla swoich obiektów i użyj array_filter, aby wyrzucić rzeczy, które funkcja już widziała.
źródło
array_unique
używany z pracami SORT_REGULAR, zobacz moją odpowiedź poniżej.To mój sposób na porównywanie obiektów o prostych właściwościach, a jednocześnie na otrzymanie unikalnej kolekcji:
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);
Wyświetli:
array (size=2) 'foo' => object(Role)[1165] private 'name' => string 'foo' (length=3) 'bar' => object(Role)[1166] private 'name' => string 'bar' (length=3)
źródło
Jeśli masz tablicę obiektów i chcesz przefiltrować tę kolekcję, aby usunąć wszystkie duplikaty, możesz użyć array_filter z funkcją anonimową:
$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; });
Ważne: Pamiętaj, że musisz przekazać
$tmp
tablicę jako odniesienie do funkcji wywołania zwrotnego filtru, w przeciwnym razie nie zadziałaźródło