オブジェクトのarray_uniqueのようなメソッドはありますか?マージする「Role」オブジェクトを含む配列がたくさんあるので、重複を削除したいと思います:)
回答:
さて、array_unique()
要素の文字列値を比較します:
注:2つの要素は
(string) $elem1 === (string) $elem2
、文字列表現が同じである場合にのみ等しいと見なされ、最初の要素が使用されます。
したがって__toString()
、クラスにメソッドを実装し、同じロールに対して同じ値を出力するようにしてください。
class Role {
private $name;
//.....
public function __toString() {
return $this->name;
}
}
これは、2つの役割が同じ名前である場合、それらが等しいと見なします。
array_unique
も__toString()
比較もしないからです。__toString()
文字列コンテキストで使用されたときにオブジェクトインスタンスがどのように動作するかを定義し、array_unique
重複する値が削除された入力配列を返します。これは内部的に比較を使用するだけです。
echo $object
、この__toString
方法も使用します。
__toString()
すべてのオブジェクトにメソッドを追加することはSORT_REGULAR
、array_uniqueにフラグを追加するよりもはるかに面倒です。MatthieuNapoliの回答を参照してください。ほかに__toString()
方法は、オブジェクトの比較のために使用されている他の多くのユースケースを持っているので、このかもしれないがさえ可能ではありません。
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
警告:厳密な比較ではなく、 "=="の比較を使用します( "===")。
したがって、オブジェクトの配列内の重複を削除する場合は、オブジェクトのID(インスタンス)を比較するのではなく、各オブジェクトのプロパティを比較することに注意してください。
==
)と同一性(===
)の比較の違いは示されていません(違いを示す$bam->prop = 'test2';
必要が'test1'
あります)。例については、codepad.viper-7.com / 8NxWhGを参照してください。
in_array
$strict
パラメータを使用する必要があります!それ以外の場合は、「===」の代わりに「==」を使用してオブジェクトを比較します。詳細はこちら:fr2.php.net/manual/fr/function.in-array.php
配列内の重複オブジェクトを削除する方法は次のとおりです。
<?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);
特定の属性に基づいてオブジェクトをフィルタリングする場合は、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;
});
ここから:http://php.net/manual/en/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);
}
?>
オブジェクトのインデックス付き配列があり、各オブジェクトの特定のプロパティを比較して重複を削除したい場合は、次のような関数を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
)
)
重複したインスタンス(つまり、「===」の比較)を配列からフィルタリングする必要がある場合の正気で高速な方法。
は:
//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
これは非常に簡単な解決策です。
$ids = array();
foreach ($relate->posts as $key => $value) {
if (!empty($ids[$value->ID])) { unset($relate->posts[$key]); }
else{ $ids[$value->ID] = 1; }
}
array_uniqueは、要素を文字列にキャストして比較することで機能します。オブジェクトが一意に文字列にキャストされない限り、array_uniqueでは機能しません。
代わりに、オブジェクトにステートフル比較関数を実装し、array_filterを使用して、関数がすでに見たものを破棄します。
array_unique
SORT_REGULARで使用すると、以下の私の答えを参照してください。
これは、単純なプロパティを持つオブジェクトを比較すると同時に、一意のコレクションを受け取る私の方法です。
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)
オブジェクトの配列があり、このコレクションをフィルタリングしてすべての重複を削除する場合は、匿名関数で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
フィルターコールバック関数への参照として配列を渡す必要があることに注意してください。そうしないと機能しません。