Gibt es eine Methode wie array_unique für Objekte? Ich habe eine Reihe von Arrays mit 'Rollen'-Objekten, die ich zusammenführe, und dann möchte ich die Duplikate entfernen :)
Nun, array_unique()vergleicht den String - Wert der Elemente:
Hinweis : Zwei Elemente werden genau dann als gleich angesehen, wenn bei gleicher (string) $elem1 === (string) $elem2Zeichenfolgendarstellung das erste Element verwendet wird.
Stellen Sie daher sicher, dass die __toString()Methode in Ihrer Klasse implementiert ist und dass sie denselben Wert für gleiche Rollen ausgibt, z
@ Jacob, weil weder array_uniquenoch __toString()etwas vergleichen. __toString()Definiert, wie sich eine Objektinstanz bei Verwendung in einem Zeichenfolgenkontext verhalten soll, und array_uniquegibt das Eingabearray mit entfernten doppelten Werten zurück. Es wird nur intern ein Vergleich verwendet .
Gordon
1
@ Jacob Relkin: Es ist kein Komparator. Es ist die Zeichenfolgendarstellung des Objekts. Ich denke, sie verwenden dies, da Sie jeden Typ, jedes Objekt usw. in eine Zeichenfolge konvertieren können. Die String-Methode selbst für ein Objekt wird jedoch nicht nur von dieser Funktion verwendet. ZB echo $objectverwendet auch die __toStringMethode.
Felix Kling
3
Das Hinzufügen von __toString()Methoden zu all Ihren Objekten ist viel schmerzhafter als das Hinzufügen eines SORT_REGULARFlags zu array_unique, siehe Matthieu Napoli seine Antwort. Außerdem hat eine __toString()Methode viele andere Anwendungsfälle, die dann für den Objektvergleich verwendet werden, so dass dies möglicherweise nicht einmal möglich ist.
Flip
154
array_uniquearbeitet mit einer Reihe von Objekten mit SORT_REGULAR:
classMyClass{
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));
Warnung : Es wird der Vergleich "==" verwendet, nicht der strikte Vergleich ("===").
Wenn Sie also Duplikate in einem Array von Objekten entfernen möchten, achten Sie darauf, dass die einzelnen Objekteigenschaften verglichen werden und nicht die Objektidentität (Instanz).
Diese Antwort ist viel besser als die akzeptierte Antwort. Das Beispiel zeigt jedoch nicht den Unterschied zwischen dem Vergleich von Wert ( ==) oder Identität ( ===) aufgrund von $bam->prop = 'test2';(sollte 'test1'den Unterschied darstellen). Ein Beispiel finden Sie unter codepad.viper-7.com/8NxWhG .
Sollte die akzeptierte Antwort sein. Auch dies viel schneller als mit __toString (). Das Vergleichsergebnis finden Sie unter: sandbox.onlinephpfunctions.com/code/… .
LucaM
1
Achten Sie darauf, Objekte mit array_unique () zu vergleichen. Die Funktion wendet einen umfassenden Vergleich an, der zum Absturz Ihres Servers führen kann, wenn zu viel Rekursion erforderlich ist. Ich sehe Sie als Doctrine-Entitäten. Identifizieren Sie besser, was Ihr Objekt einzigartig macht, und indizieren Sie Ihre Objekte damit. Wenn Ihre Objekte beispielsweise eine Zeichenfolgenkennung haben, erstellen Sie ein Array mit dieser Kennung als Schlüssel.
Olvlvl
31
Diese Antwort wird verwendet, in_array()da die Art des Vergleichens von Objekten in PHP 5 dies ermöglicht. Um dieses Objektvergleichsverhalten nutzen zu können, muss das Array nur Objekte enthalten. Dies scheint hier jedoch der Fall zu sein.
Funktioniert gut, es ist vielleicht schneller als das andere (weiß es nicht wirklich), aber ich werde deins verwenden, weil ich keine zusätzliche Funktion dafür übernehmen muss: D
Gigala
Beim Vergleichen von Objekten müssen sie die gleiche Anzahl von Feldern und identische Schlüssel / Wert-Paare haben, um als gleich richtig angesehen zu werden. Was ich
Die Nichtverwendung des strengen Parameters war hier eine bewusste Wahl. Ich wollte "gleiche" Objekte finden, nicht unbedingt die gleiche Instanz eines Objekts. Dies wird in dem in der Antwort erwähnten Link erklärt, der besagt: " Bei Verwendung des Vergleichsoperators (==) werden Objektvariablen auf einfache Weise verglichen, nämlich: Zwei Objektinstanzen sind gleich, wenn sie dieselben Attribute und Werte haben. und sind Instanzen derselben Klasse. "
salathe
Klappt wunderbar! Vielen Dank
Gronaz
16
So entfernen Sie doppelte Objekte in einem Array:
<?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);
Das ist für mich die beste Lösung! Ich verwende diese Lösung für meine Website searchengine (füge 2 Abfrageergebnisse aus einer Datenbank zusammen). Zuerst habe ich die Ergebnisse für alle Suchbegriffe und füge sie mit den Ergebnissen einiger Suchbegriffe zusammen. Mit dieser Lösung habe ich die wichtigsten Ergebnisse zuerst, hinzugefügt durch einzigartige andere Lösungen.
Wenn Sie über ein indiziertes Array von Objekten verfügen und Duplikate durch Vergleichen einer bestimmten Eigenschaft in jedem Objekt entfernen möchten, kann eine Funktion wie die remove_duplicate_models()folgende verwendet werden.
array_unique wandelt die Elemente in einen String um und führt einen Vergleich durch. Wenn Ihre Objekte nicht eindeutig in Zeichenfolgen umgewandelt werden, funktionieren sie nicht mit array_unique.
Implementieren Sie stattdessen eine statusbehaftete Vergleichsfunktion für Ihre Objekte und verwenden Sie array_filter , um Dinge wegzuwerfen, die die Funktion bereits gesehen hat.
Wenn Sie ein Array von Objekten haben und diese Sammlung filtern möchten, um alle Duplikate zu entfernen, können Sie array_filter mit anonymer Funktion verwenden:
$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();
returntrue;
}
returnfalse;
});
Wichtig: Denken Sie daran, dass Sie das $tmpArray als Referenz für Ihre Filter-Rückruffunktion übergeben müssen, da es sonst nicht funktioniert
Antworten:
Nun,
array_unique()
vergleicht den String - Wert der Elemente:Stellen Sie daher sicher, dass die
__toString()
Methode in Ihrer Klasse implementiert ist und dass sie denselben Wert für gleiche Rollen ausgibt, zclass Role { private $name; //..... public function __toString() { return $this->name; } }
Dies würde zwei Rollen als gleich betrachten, wenn sie denselben Namen haben.
quelle
array_unique
noch__toString()
etwas vergleichen.__toString()
Definiert, wie sich eine Objektinstanz bei Verwendung in einem Zeichenfolgenkontext verhalten soll, undarray_unique
gibt das Eingabearray mit entfernten doppelten Werten zurück. Es wird nur intern ein Vergleich verwendet .echo $object
verwendet auch die__toString
Methode.__toString()
Methoden zu all Ihren Objekten ist viel schmerzhafter als das Hinzufügen einesSORT_REGULAR
Flags zu array_unique, siehe Matthieu Napoli seine Antwort. Außerdem hat eine__toString()
Methode viele andere Anwendungsfälle, die dann für den Objektvergleich verwendet werden, so dass dies möglicherweise nicht einmal möglich ist.array_unique
arbeitet mit einer Reihe von Objekten mitSORT_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));
Wird drucken:
Array ( [0] => MyClass Object ( [prop] => test1 ) [2] => MyClass Object ( [prop] => test2 ) )
Sehen Sie es hier in Aktion: http://3v4l.org/VvonH#v529
Warnung : Es wird der Vergleich "==" verwendet, nicht der strikte Vergleich ("===").
Wenn Sie also Duplikate in einem Array von Objekten entfernen möchten, achten Sie darauf, dass die einzelnen Objekteigenschaften verglichen werden und nicht die Objektidentität (Instanz).
quelle
==
) oder Identität (===
) aufgrund von$bam->prop = 'test2';
(sollte'test1'
den Unterschied darstellen). Ein Beispiel finden Sie unter codepad.viper-7.com/8NxWhG .Diese Antwort wird verwendet,
in_array()
da die Art des Vergleichens von Objekten in PHP 5 dies ermöglicht. Um dieses Objektvergleichsverhalten nutzen zu können, muss das Array nur Objekte enthalten. Dies scheint hier jedoch der Fall zu sein.$merged = array_merge($arr, $arr2); $final = array(); foreach ($merged as $current) { if ( ! in_array($current, $final)) { $final[] = $current; } } var_dump($final);
quelle
in_array
sollte den$strict
Parameter verwenden! Andernfalls vergleichen Sie Objekte mit "==" anstelle von "===". Mehr hier: fr2.php.net/manual/fr/function.in-array.phpSo entfernen Sie doppelte Objekte in einem Array:
<?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);
quelle
Sie können auch zuerst serialisieren:
$unique = array_map( 'unserialize', array_unique( array_map( 'serialize', $array ) ) );
Ab PHP 5.2.9 können Sie nur optional verwenden
sort_flag SORT_REGULAR
:quelle
Sie können auch die Funktion array_filter verwenden, wenn Sie Objekte anhand eines bestimmten Attributs filtern möchten:
//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; });
quelle
Von hier: http://php.net/manual/en/function.array-unique.php#75307
Dieser würde auch mit Objekten und Arrays arbeiten.
<?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); } ?>
quelle
Wenn Sie über ein indiziertes Array von Objekten verfügen und Duplikate durch Vergleichen einer bestimmten Eigenschaft in jedem Objekt entfernen möchten, kann eine Funktion wie die
remove_duplicate_models()
folgende verwendet werden.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 ) );
Das Ergebnis ist:
Array ( [0] => Car Object ( [model:Car:private] => Mustang ) [1] => Car Object ( [model:Car:private] => F-150 ) [2] => Car Object ( [model:Car:private] => Taurus ) )
quelle
Dies ist eine sehr einfache Lösung:
$ids = array(); foreach ($relate->posts as $key => $value) { if (!empty($ids[$value->ID])) { unset($relate->posts[$key]); } else{ $ids[$value->ID] = 1; } }
quelle
array_unique wandelt die Elemente in einen String um und führt einen Vergleich durch. Wenn Ihre Objekte nicht eindeutig in Zeichenfolgen umgewandelt werden, funktionieren sie nicht mit array_unique.
Implementieren Sie stattdessen eine statusbehaftete Vergleichsfunktion für Ihre Objekte und verwenden Sie array_filter , um Dinge wegzuwerfen, die die Funktion bereits gesehen hat.
quelle
array_unique
verwendet mit SORT_REGULAR funktioniert, siehe meine Antwort unten.vernünftiger und schneller Weg, wenn Sie doppelte Instanzen (dh "===" Vergleich) aus dem Array herausfiltern müssen und:
ist:
//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
quelle
Auf diese Weise vergleiche ich Objekte mit einfachen Eigenschaften und erhalte gleichzeitig eine eindeutige Sammlung:
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);
Wird ausgegeben:
array (size=2) 'foo' => object(Role)[1165] private 'name' => string 'foo' (length=3) 'bar' => object(Role)[1166] private 'name' => string 'bar' (length=3)
quelle
Wenn Sie ein Array von Objekten haben und diese Sammlung filtern möchten, um alle Duplikate zu entfernen, können Sie array_filter mit anonymer Funktion verwenden:
$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; });
Wichtig: Denken Sie daran, dass Sie das
$tmp
Array als Referenz für Ihre Filter-Rückruffunktion übergeben müssen, da es sonst nicht funktioniertquelle