Có phương thức nào giống như array_unique cho các đối tượng không? Tôi có một loạt các mảng với các đối tượng 'Vai trò' mà tôi hợp nhất và sau đó tôi muốn loại bỏ các bản sao :)
Câu trả lời:
Vâng, array_unique()
so sánh giá trị chuỗi của các phần tử:
Lưu ý : Hai phần tử được coi là bằng nhau nếu và chỉ khi
(string) $elem1 === (string) $elem2
nghĩa là khi biểu diễn chuỗi giống nhau, phần tử đầu tiên sẽ được sử dụng.
Vì vậy, hãy đảm bảo triển khai __toString()
phương thức trong lớp của bạn và nó xuất ra cùng một giá trị cho các vai trò như nhau, ví dụ:
class Role {
private $name;
//.....
public function __toString() {
return $this->name;
}
}
Điều này sẽ coi hai vai trò như nhau nếu chúng có cùng tên.
array_unique
và cũng không __toString()
so sánh bất cứ điều gì. __toString()
xác định cách một cá thể đối tượng phải hoạt động khi được sử dụng trong ngữ cảnh chuỗi và array_unique
trả về mảng đầu vào với các giá trị trùng lặp đã bị loại bỏ. Nó chỉ sử dụng so sánh cho điều này trong nội bộ.
echo $object
cũng sử dụng __toString
phương pháp.
__toString()
phương thức cho tất cả các đối tượng của bạn sẽ khó hơn nhiều, sau đó chỉ cần thêm một SORT_REGULAR
cờ vào array_unique, hãy xem câu trả lời của Matthieu Napoli. Bên cạnh một __toString()
phương thức có nhiều trường hợp sử dụng khác sau đó được sử dụng để so sánh đối tượng, vì vậy điều này thậm chí có thể không thực hiện được.
array_unique
hoạt động với một mảng các đối tượng bằng cách sử dụng 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));
Sẽ in:
Array (
[0] => MyClass Object
(
[prop] => test1
)
[2] => MyClass Object
(
[prop] => test2
)
)
Xem nó hoạt động tại đây: http://3v4l.org/VvonH#v529
Cảnh báo : nó sẽ sử dụng so sánh "==", không phải so sánh chặt chẽ ("===").
Vì vậy, nếu bạn muốn loại bỏ các bản sao bên trong một mảng đối tượng, hãy cẩn thận rằng nó sẽ so sánh từng thuộc tính đối tượng, không so sánh danh tính đối tượng (cá thể).
==
) hoặc ID ( ===
) vì $bam->prop = 'test2';
(phải là 'test1'
để thể hiện sự khác biệt). Xem codepad.viper-7.com/8NxWhG để làm ví dụ.
Câu trả lời này sử dụng in_array()
vì bản chất của việc so sánh các đối tượng trong PHP 5 cho phép chúng ta làm như vậy. Việc sử dụng hành vi so sánh đối tượng này yêu cầu mảng chỉ chứa các đối tượng, nhưng điều đó dường như là trường hợp ở đây.
$merged = array_merge($arr, $arr2);
$final = array();
foreach ($merged as $current) {
if ( ! in_array($current, $final)) {
$final[] = $current;
}
}
var_dump($final);
in_array
nên sử dụng $strict
tham số! Nếu không, bạn so sánh các đối tượng bằng cách sử dụng "==" thay vì "===". Xem thêm tại đây: fr2.php.net/manual/fr/ Chức năng.in
Đây là một cách để loại bỏ các đối tượng trùng lặp trong một mảng:
<?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);
Bạn cũng có thể sử dụng hàm array_filter, nếu bạn muốn lọc các đối tượng dựa trên một thuộc tính cụ thể:
//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;
});
Từ đây: http://php.net/manual/en/ Chức năng.array-unique.php#75307
Cái này cũng sẽ hoạt động với các đối tượng và mảng.
<?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);
}
?>
Nếu bạn có một mảng đối tượng được lập chỉ mục và bạn muốn loại bỏ các bản sao bằng cách so sánh một thuộc tính cụ thể trong mỗi đối tượng, bạn remove_duplicate_models()
có thể sử dụng một hàm như hàm dưới đây.
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 ) );
Kết quả là:
Array
(
[0] => Car Object
(
[model:Car:private] => Mustang
)
[1] => Car Object
(
[model:Car:private] => F-150
)
[2] => Car Object
(
[model:Car:private] => Taurus
)
)
một cách lành mạnh và nhanh chóng nếu bạn cần lọc các trường hợp trùng lặp (tức là so sánh "===") ra khỏi mảng và:
Là:
//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
Đây là giải pháp rất đơn giản:
$ids = array();
foreach ($relate->posts as $key => $value) {
if (!empty($ids[$value->ID])) { unset($relate->posts[$key]); }
else{ $ids[$value->ID] = 1; }
}
array_unique hoạt động bằng cách chuyển các phần tử thành một chuỗi và thực hiện so sánh. Trừ khi các đối tượng của bạn được truyền duy nhất thành chuỗi, thì chúng sẽ không hoạt động với array_unique.
Thay vào đó, hãy triển khai một hàm so sánh trạng thái cho các đối tượng của bạn và sử dụng array_filter để loại bỏ những thứ mà hàm đã thấy.
array_unique
được sử dụng với SORT_REGULAR hoạt động, hãy xem câu trả lời của tôi bên dưới.
Đây là cách của tôi để so sánh các đối tượng có thuộc tính đơn giản và đồng thời nhận được một bộ sưu tập duy nhất:
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);
Sẽ xuất:
array (size=2)
'foo' =>
object(Role)[1165]
private 'name' => string 'foo' (length=3)
'bar' =>
object(Role)[1166]
private 'name' => string 'bar' (length=3)
Nếu bạn có mảng đối tượng và bạn muốn lọc bộ sưu tập này để loại bỏ tất cả các bản sao, bạn có thể sử dụng array_filter với chức năng ẩn danh:
$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;
});
Quan trọng: Hãy nhớ rằng bạn phải chuyển $tmp
mảng làm tham chiếu để lọc hàm gọi lại nếu không nó sẽ không hoạt động