PHPで多次元配列から重複する値を削除する方法


306

PHPの多次元配列から重複する値を削除するにはどうすればよいですか?

配列の例:

Array
(
    [0] => Array
    (
        [0] => abc
        [1] => def
    )

    [1] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [2] => Array
    (
        [0] => mno
        [1] => pql
    )

    [3] => Array
    (
        [0] => abc
        [1] => def
    )

    [4] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [5] => Array
    (
        [0] => mno
        [1] => pql
    )

)

回答:


637

ここに別の方法があります。中間変数は保存されません。

これを使用して、さまざまな重複するクエリからの結果の重複を排除しました。

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

23
unserializeのため、これは遅くなり、アレイが大きく複雑になるほど遅くなります。私がarray_intersect_keyを使用した理由があります(この回答の半年前)。
OIS 2013

11
@OISはよくテストされましたが、タイプミスはありましたが、うまくいきました。ありがとう$!
trevorkavanaugh 2013年

3
連続したインデックスが必要な場合は、array_valuesを使用します。つまり、$ input = array_values(array_map( "unserialize"、array_unique(array_map( "serialize"、$ input))));
lbsweek 2014

4
今日ではおそらく、PHPのシリアライゼーションの代わりにjson_encodeとjson_decodeを選択するでしょう。提供された値のための利点を持っている必要がありますし、あなたはシリアル化/アンシリアライズ船とし、最も可能性が高いが不要であることをPHPのシリアライズの詳細に実行されません。
hakre 2014

2
serialize(array('a' => '1', 'b' => '1'))は異なることに注意してくださいserialize(array('b' => '1', 'a' => '1'))。このオプションは、setsまたはとして使用されるアレイでは失敗します(hash)maps
Andras Gyomrey

240

5.2.9以降でarray_unique()は、SORT_REGULARフラグを次のように使用すれば使用できます。

array_unique($array, SORT_REGULAR);

これにより、関数は要素が等しいかどうか$a == $bを、まるで使用されているかのように比較します。これは、ケースに最適です。

出力

Array
(
    [0] => Array
        (
            [0] => abc
            [1] => def
        )

    [1] => Array
        (
            [0] => ghi
            [1] => jkl
        )

    [2] => Array
        (
            [0] => mno
            [1] => pql
        )

)

ただし、ドキュメントには次のように記載されています。

array_unique() 多次元配列で動作するようには設計されていません。


2
これは受け入れられたものよりも速くて明確な解決策だと思います!これに投票しましょう!:)うーんPHPのサイト上で我々は...それは非常に速く、私は思っていないことがわかります
Andron

4
奇妙なことに、SORT_REGULARフラグを使用しても、重複した配列を削除することはできません。
ステファン

4
@Stefanその通りです。正しい結果が得られていないようだが、それはので、それはおそらくバグだPHP 7で動作します = /
ジャック・

4
これは私の場合にも機能するようですが、array_unique()docでこのメモに悩まされている人はいますか?php.net/manual/en/...
Arleighヒックス

2
:あなたは右、これはバグはPHP 5.6.23のようですね@Jack eval.in/645675:しかし、PHP 7.0.8で修正されてeval.in/645676
ザックモリス

63

同様の問題がありましたが、100%有効な解決策を見つけました。

<?php
    function super_unique($array,$key)
    {
       $temp_array = [];
       foreach ($array as &$v) {
           if (!isset($temp_array[$v[$key]]))
           $temp_array[$v[$key]] =& $v;
       }
       $array = array_values($temp_array);
       return $array;

    }


$arr="";
$arr[0]['id']=0;
$arr[0]['titel']="ABC";
$arr[1]['id']=1;
$arr[1]['titel']="DEF";
$arr[2]['id']=2;
$arr[2]['titel']="ABC";
$arr[3]['id']=3;
$arr[3]['titel']="XYZ";

echo "<pre>";
print_r($arr);
echo "unique*********************<br/>";
print_r(super_unique($arr,'titel'));

?>

1
これは別の質問に答えます。ここを参照してください:stackoverflow.com/questions/4585208/...
OIS

素晴らしい機能!オブジェクトを処理する場合:if(!isset($ array-> $ v-> $ key))$ array [$ v-> $ key] =&$ v;
Playnox 2016年

35

別の方法。キーも保持します。

function array_unique_multidimensional($input)
{
    $serialized = array_map('serialize', $input);
    $unique = array_unique($serialized);
    return array_intersect_key($input, $unique);
}

大規模な配列の場合、この方法は多くの場合、受け入れられている回答よりも少なくとも50%高速です。
Lorien Brune

21

array_unique()ドキュメントに関するユーザーのコメントには、これに対する多くの解決策があります。以下はその1つです。

kennsnsn at rbnsn dot com
27-Sep-2005 12:09

マルチディメンション化された配列のためのさらに別のArray_Unique。私はこれを2次元の配列でのみテストしましたが、多分一般化するか、再帰を使用するようにすることができます。

この関数は、serialize、array_unique、およびunserialize関数を使用して作業を行います。


function multi_unique($array) {
    foreach ($array as $k=>$na)
        $new[$k] = serialize($na);
    $uniq = array_unique($new);
    foreach($uniq as $k=>$ser)
        $new1[$k] = unserialize($ser);
    return ($new1);
}

これはhttp://ca3.php.net/manual/en/function.array-unique.php#57202からです。


18

「重複を削除する」が「重複を削除するが、1つは許可する」を意味する場合、解決策はarray_unique(...)まず「識別子列」にを適用し、次に列配列から削除されたすべてのキーを元の配列で削除することです。 :

$array = [
    [
        'id' => '123',
        'foo' => 'aaa',
        'bar' => 'bbb'
    ],
    [
        'id' => '123',
        'foo' => 'ccc',
        'bar' => 'ddd'
    ],
    [
        'id' => '567',
        'foo' => 'eee',
        'bar' => 'fff'
    ]
];

$ids = array_column($array, 'id');
$ids = array_unique($ids);
$array = array_filter($array, function ($key, $value) use ($ids) {
    return in_array($value, array_keys($ids));
}, ARRAY_FILTER_USE_BOTH);

結果は次のとおりです。

Array
(
    [0] => Array
        (
            [id] => 123
            [foo] => aaa
            [bar] => bbb
        )

    [2] => Array
        (
            [id] => 567
            [foo] => eee
            [bar] => fff
        )

)

18
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => john
        )

    [1] => Array
        (
            [id] => 2
            [name] => smith
        )

    [2] => Array
        (
            [id] => 3
            [name] => john
        )

    [3] => Array
        (
            [id] => 4
            [name] => robert
        )

)

$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);

これにより、重複した名前が配列から削除されます。キーによって一意


$arrayキーが「0」で始まることを確認してください。が前の配列操作の結果である$array場合、のキーが別の番号で始まる可能性$arrayがあります。array_valuesキーを「0」にリセットするために使用します
stevevance


4

2番目のパラメーターとしてSORT_REGULARオプションを使用するだけです。

$uniqueArray = array_unique($array, SORT_REGULAR);

1
(@ r3wtは、ドキュメントごとのように正確であるが)PHP 5はバグを持っているのでSORT_REGULARのみ、実行可能な例示のための答えに私のコメントを参照してくださいPHP 7で動作しますstackoverflow.com/questions/307674/...
ザックモリス

なぜこれを追加するのですか?それはあなたより年上の年であり、この答えは、同じです:stackoverflow.com/a/18373723/870729
random_user_name

3

mysqli idなどの特定のキーの重複を排除する必要がある場合は、簡単な関数を次に示します

function search_array_compact($data,$key){
    $compact = [];
    foreach($data as $row){
        if(!in_array($row[$key],$compact)){
            $compact[] = $row;
        }
    }
    return $compact;
}

ボーナスポイント キーの配列を渡して外側のforeachを追加できますが、追加のキーごとに2倍遅くなります。


3

多次元配列を一意にする非常に簡単で論理的な方法は次のとおりです。

次のような配列がある場合:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value1
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value4
        )
)

foreachこれを解決するために使用:

foreach($array as $k=>$v){
    $unique=array_unique($v);
    $array[$k]=$unique;
}

次の結果が得られます。

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
            [4] => Value4
        )
)

キーの順序を変更したい場合は、

foreach($array as $k=>$v){
    $unique= array_values(array_unique($v));
    $array[$k]=$unique;
}

この操作により、次のように配置されたキー値が得られます。

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
            [3] => Value4
        )
)

これですべてがクリアされることを願っています。


2

次のような配列がある場合:

(usersはアレイの名前です)

Array=>
 [0] => (array)
   'user' => 'john'
   'age' => '23'
 [1] => (array)
  'user' => 'jane'
  'age' => '20'
 [2]=> (array)
  'user' => 'john'
  'age' => '23'

そしてあなたは重複を削除したい...その後:

$serialized = array();
for ($i=0; $i < sizeof($users); $i++) { 
  $test = in_array($users['user'], $serialized);
    if ($test == false) {
      $serialized[] = $users['user'];
    }
 }

ソリューションにすることができます:P


1

読みやすいソリューションで、おそらく最も効率的ではありません。

function arrayUnique($myArray){
    if(!is_array($myArray))
        return $myArray;

    foreach ($myArray as &$myvalue){
        $myvalue=serialize($myvalue);
    }

    $myArray=array_unique($myArray);

    foreach ($myArray as &$myvalue){
        $myvalue=unserialize($myvalue);
    }

    return $myArray;

} 

1

人々がarray_unique()非常に遅いと言っているように、これが私が1レベルの多次元配列に使用するスニペットです。

$serialized_array = array_map("serialize", $input);

foreach ($serialized_array as $key => $val) {
     $result[$val] = true;
}

$output = array_map("unserialize", (array_keys($result)));

php.net関数ページの最初のユーザー投稿ノートをarray_unique() 参照


アヌジ、あなたの答えを編集していただけませんか?バグがあります。終了するはずです $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasherご入力ありがとうございます。変更を加えたところ、問題なく動作しました。:)
アヌジ

1

多くの人から、Unique多次元配列の作り方を尋ねられました。私はあなたのコメントから参照を取りました、そしてそれは私を助けます。

まず第一に、あなたの解決のために@jeromegamez @daveilersに感謝します。しかし、答えを出すたびに、この「シリアライズ」と「アンシリアライズ」がどのように機能するかを尋ねられました。その理由を私はあなたと共有して、より多くの人々がこの背後にある概念を理解するのに役立つようにしたいと思います。

なぜ 'serialize'と 'unserialize'を段階的に使うのかを説明しています:

ステップ1:多次元配列を1次元配列に変換する

多次元配列を1次元配列に変換するには、まず配列内のすべての要素(ネストされた配列を含む)のバイトストリーム表現を生成します。serialize()関数は、値のバイトストリーム表現を生成できます。すべての要素のバイトストリーム表現を生成するには、array_map()関数内のserialize()関数をコールバック関数として呼び出します。結果は、多次元配列のレベル数に関係なく、1次元配列になります。

ステップ2:値を一意にする

この1次元配列を一意にするには、array_unique()関数を使用します。

ステップ3:多次元配列に戻す

配列は一意になりましたが、値はバイトストリーム表現のように見えます。多次元配列に戻すには、unserialize()関数を使用します。

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

本当にありがとうございました。


0

シリアル化および一意化の代替手段

$test = [
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
];

$result = array_reduce(
    $test,
    function($carry,$item){
        if(!in_array($item,$carry)) {
            array_push($carry,$item);
        }
        return $carry;
    },
    []
);

var_dump($result);

/*
 php unique.php
array(3) {
    [0] =>
        array(2) {
            [0] =>
                string(3) "abc"
            [1] =>
                string(3) "def"
        }
    [1] =>
        array(2) {
            [0] =>
                string(3) "ghi"
            [1] =>
                string(3) "jkl"
        }
    [2] =>
        array(2) {
              [0] =>
                  string(3) "mno"
              [1] =>
                  string(3) "pql"
        }
}

* /


0

このような配列がある場合

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => b
),
[3] => array
(
    [subject] => d
    [object] => c
),
[4] => array
(
    [subject] => c
    [object] => a
),
[5] => array
(
    [subject] => c
    [object] => d
)
)

そして、あなたはこのような配列を得たいです:

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => c
)
)

または

data = array
(
[0] => array
(
    [subject] => d
    [object] => b
),
[1] => array
(
    [subject] => c
    [object] => a
),
[2] => array
(
    [subject] => c
    [object] => d
)
)

次のコードが役立ちます

    $data1 = array();
    $data1 = $data;
    for($q=0;$q<count($data);$q++)
    {
            for($p=0;$p<count($data1);$p++)
            {
                    if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"]))
                    {
                            $data1[$p]["subject"] = $data[$q]["subject"];
                            $data1[$p]["object"] = $data[$q]["object"];
                    }
            }
    }
    $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1))));
    $data = $data1;

0

私はこの問題をよく考え、最適なソリューションは2つのルールに従う必要があると判断しました。

  1. スケーラビリティーのために、アレイを適切に変更します。新しいアレイにコピーしない
  2. パフォーマンスのために、各比較は一度だけ行う必要があります

これを念頭に置き、PHPの癖をすべて踏まえて、以下に私が考え出したソリューションを示します。他のいくつかの回答とは異なり、必要なキーに基づいて要素を削除する機能があります。入力配列は数値キーであることが期待されています。

$count_array = count($input);
for ($i = 0; $i < $count_array; $i++) {
    if (isset($input[$i])) {
        for ($j = $i+1; $j < $count_array; $j++) {
            if (isset($input[$j])) {
                //this is where you do your comparison for dupes
                if ($input[$i]['checksum'] == $input[$j]['checksum']) {
                    unset($input[$j]);
                }
            }
        }
    }
}

唯一の欠点は、反復が完了したときにキーの順序が正しくないことです。後でforeachループのみを使用する場合は問題ありませんが、forループを使用する必要がある場合は$input = array_values($input);、上記の後に配置してキーの番号を付け直すことができます。


0

正しいとマークされた回答に基づいて、私の回答を追加します。インデックスをリセットするためだけに追加された小さなコード-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.