オブジェクトのarray_unique?


回答:


98

さて、array_unique()要素の文字列値を比較します:

:2つの要素は(string) $elem1 === (string) $elem2、文字列表現が同じである場合にのみ等しいと見なされ、最初の要素が使用されます。

したがって__toString()、クラスにメソッドを実装し、同じロールに対して同じ値を出力するようにしてください。

class Role {
    private $name;

    //.....

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

}

これは、2つの役割が同じ名前である場合、それらが等しいと見なします。


2
@ジェイコブは何array_unique__toString()比較もしないからです。__toString()文字列コンテキストで使用されたときにオブジェクトインスタンスがどのように動作するかを定義し、array_unique重複する値が削除された入力配列を返します。これ内部的に比較を使用するだけです。
ゴードン

1
@Jacob Relkin:コンパレータではありません。これは、オブジェクトの文字列表現です。どんなタイプやオブジェクトなどでも文字列に変換できるので、これを使っていると思います。ただし、オブジェクトの文字列メソッド自体は、この関数で使用されるだけではありません。たとえばecho $object、この__toString方法も使用します。
Felix Kling 2010年

3
__toString()すべてのオブジェクトにメソッドを追加することはSORT_REGULAR、array_uniqueにフラグを追加するよりもはるかに面倒です。MatthieuNapoliの回答を参照してください。ほかに__toString()方法は、オブジェクトの比較のために使用されている他の多くのユースケースを持っているので、このかもしれないがさえ可能ではありません。
2014年

156

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(インスタンス)を比較するのではなく、各オブジェクトのプロパティを比較することに注意してください。


12
この答えは、受け入れられた答えよりもはるかに優れています。ただし、この例では、値(==)と同一性(===)の比較の違いは示されていません(違いを示す$bam->prop = 'test2';必要が'test1'あります)。例については、codepad.viper-7.com / 8NxWhGを参照してください。
2014年

@vishalは公式ドキュメントをご覧ください
Matthieu Napoli

1
あなたは私を救ってくれました、TnQ:*
Saman Sattari

1
受け入れられた答えでなければなりません。また、これは__toString()を使用するよりもはるかに高速です。比較結果については、sandbox.onlinephpfunctions.com / code / を参照してください。
LucaM 2016

1
オブジェクトをarray_unique()と比較することに注意してください。この関数は詳細な比較を適用します。再帰が多すぎると、サーバーがクラッシュする可能性があります。私はDoctrineエンティティを見ています。オブジェクトを一意にするものをより適切に特定し、それを使用してオブジェクトにインデックスを付けます。たとえば、オブジェクトに文字列識別子がある場合は、その識別子をキーとして配列を作成します。
olvlvl 2017年

31

PHP 5でオブジェクトin_array()比較する性質があるため、この回答は使用します。このオブジェクト比較動作を利用するには、配列にオブジェクトのみが含まれている必要がありますが、ここではそうであるように見えます。

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

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

var_dump($final);

1
うまく機能します、それは他のものより速いかもしれません(本当にわかりません)が、私はそれのために余分な機能を作る必要がないのであなたのものを使います:D
ギガラ2013年

オブジェクトを比較する場合、同じ正しいと見なされるには、同じ量のフィールドがあり、同じキーと値のペアである必要がありますか?私が得ているのは.... 2つのオブジェクトがあり、そのうちの1つに1つの追加フィールドがある場合、それらのオブジェクトは「同じ」とは見なされません
ChuckKelly 2013

1
in_array$strictパラメータを使用する必要があります!それ以外の場合は、「===」の代わりに「==」を使用してオブジェクトを比較します。詳細はこちら:fr2.php.net/manual/fr/function.in-array.php
Matthieu Napoli

1
ここでは、厳密なパラメーターを使用しないことを意図的に選択しました。オブジェクトの同じインスタンスである必要なく、「等しい」オブジェクトを見つけたかったのです。これは、回答に記載されているリンクで説明されています。「比較演算子(==)を使用すると、オブジェクト変数は簡単な方法で比較されます。つまり、2つのオブジェクトインスタンスが同じ属性と値を持っている場合、それらは等しいです。と同じクラスのインスタンスです。 "
2014年

チャームのように機能します!
どうも

17

配列内の重複オブジェクトを削除する方法は次のとおりです。

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

これは私にとって最良の解決策です!私は自分のウェブサイト検索エンジンにこのソリューションを使用しています(データベースからの2つのクエリ結果をマージします)。まず、すべての検索語の結果を取得し、それらをいくつかの検索語の結果とマージします。このソリューションでは、最初に最も重要な結果が得られ、他のユニークなソリューションが追加されます。
Finduilas19年

11

最初にシリアル化することもできます。

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

PHP 5.2.9以降、オプションを使用できますsort_flag SORT_REGULAR

$unique = array_unique( $array, SORT_REGULAR );

9

特定の属性に基づいてオブジェクトをフィルタリングする場合は、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;
});

6

ここから: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);
}
?>

2

オブジェクトのインデックス付き配列があり、各オブジェクトの特定のプロパティを比較して重複を削除したい場合は、次のような関数を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
        )

)

0

重複したインスタンス(つまり、「===」の比較)を配列からフィルタリングする必要がある場合の正気で高速な方法。

  • どの配列がオブジェクトのみを保持するかは確かです
  • キーを保存する必要はありません

は:

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

これは非常に簡単な解決策です。

$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は、要素を文字列にキャストして比較することで機能します。オブジェクトが一意に文字列にキャストされない限り、array_uniqueでは機能しません。

代わりに、オブジェクトにステートフル比較関数を実装し、array_filterを使用して、関数がすでに見たものを破棄します。


私はもっ​​とエレガントな解決策(コールバックを必要としない解決策)を探していました。それにもかかわらず、あなたの答えに感謝します。
Emanuil Rusev 2011

1
array_uniqueSORT_REGULARで使用すると、以下の私の答えを参照してください。
Matthieu Napoli

-1

これは、単純なプロパティを持つオブジェクトを比較すると同時に、一意のコレクションを受け取る私の方法です。

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)

-1

オブジェクトの配列があり、このコレクションをフィルタリングしてすべての重複を削除する場合は、匿名関数で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フィルターコールバック関数への参照として配列を渡す必要があることに注意してください。そうしないと機能しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.