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
)
)
これは別の方法です。中間変数は保存されません。
これを使用して、さまざまな重複クエリからの結果を重複排除します。
$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
5.2.9以降、SORT_REGULAR
フラグを使用する場合は array_unique()
を使用できます。
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()
は多次元配列を扱うためのものではありません。
私は同様の問題を抱えていましたが、私はそれのための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'));
?>
別の方法。鍵も保存します。
function array_unique_multidimensional($input)
{
$serialized = array_map('serialize', $input);
$unique = array_unique($serialized);
return array_intersect_key($input, $unique);
}
array_unique() のドキュメントに対するユーザーのコメントには、これに対する多くの解決策があります。そのうちの一つがここにあります:
rbnsn dot comのkenrbnsn
2005年9月27日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 からです。
「重複を削除」が「重複を削除するが、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
)
)
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);
これにより、重複した名前が配列から削除されます。キーによって一意
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倍遅くなります。
2番目のパラメータとしてSORT_REGULARオプションを使用するだけです。
$uniqueArray = array_unique($array, SORT_REGULAR);
あなたがこのような配列を持っているならば:
(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
読みやすいソリューションですが、おそらく最も効率的ではありません。
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;
}
多次元配列を一意にするための非常に簡単で論理的な方法は次のとおりです。
あなたがこのような配列を持っているならば:
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
)
)
私はこれがすべてをクリアすることを願っています。
たくさんの人が私にユニークな多次元配列を作る方法を尋ねました。私はあなたのコメントから言及しました、そしてそれは私を助けます。
まず最初に、@ 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)));
ありがとうございました。
私はこの問題に多くの考えを与え、最適な解決策は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);
を付けてキーの番号を変更できます。
このような配列があれば
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;
直列化および固有の代替
$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"
}
}
* /
人々が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)));
最初のユーザーがarray_unique()
のメモを投稿しました php.netの機能ページ