Как использовать array_unique для массива массивов?
У меня есть массив
Array(
[0] => Array
(
[0] => 33
[user_id] => 33
[1] => 3
[frame_id] => 3
)
[1] => Array
(
[0] => 33
[user_id] => 33
[1] => 3
[frame_id] => 3
)
[2] => Array
(
[0] => 33
[user_id] => 33
[1] => 8
[frame_id] => 8
)
[3] => Array
(
[0] => 33
[user_id] => 33
[1] => 3
[frame_id] => 3
)
[4] => Array
(
[0] => 33
[user_id] => 33
[1] => 3
[frame_id] => 3
)
)
Как вы можете видеть, клавиша 0 совпадает с 1,3 и 4. И ключ 2 отличается от всех.
При запуске функции array_unique на них остается только
Array (
[0] => Array
(
[0] => 33
[user_id] => 33
[1] => 3
[frame_id] => 3
)
)
любые идеи, почему array_unique работает не так, как ожидалось?
Ответы
Ответ 1
Это потому, что array_unique
сравнивает элементы, используя сравнение строк. Из docs:
Примечание: рассматриваются два элемента равным тогда и только тогда, когда (строка) $elem1 === (строка) $elem2. В словах: когда строковое представление одно и то же. Будет использоваться первый элемент.
Строковое представление массива - это просто слово Array
, независимо от его содержимого.
Вы можете делать то, что хотите, используя следующее:
$arr = array(
array('user_id' => 33, 'frame_id' => 3),
array('user_id' => 33, 'frame_id' => 3),
array('user_id' => 33, 'frame_id' => 8)
);
$arr = array_intersect_key($arr, array_unique(array_map('serialize', $arr)));
//result:
array
0 =>
array
'user_id' => int 33
'user' => int 3
2 =>
array
'user_id' => int 33
'user' => int 8
Вот как это работает:
-
Каждый элемент массива сериализуется. Эта
будет уникальным на основе массива
содержание.
-
Результаты этого выполняются через array_unique
,
поэтому только массивы с уникальными
подписи остаются.
-
array_intersect_key
будет
ключи от уникальных предметов из
карта/уникальная функция (поскольку ключи исходного массива сохранены) и pull
их из исходного источника
массив.
Ответ 2
array_unique()
поддерживает только многомерные массивы в PHP 5.2.9 и выше.
Вместо этого вы можете создать хэш массива и проверить его на уникальность.
$hashes = array();
foreach($array as $val) {
$hashes[md5(serialize($val))] = $val;
}
array_unique($hashes);
Ответ 3
Здесь улучшенная версия @ryeguy answer:
<?php
$arr = array(
array('user_id' => 33, 'tmp_id' => 3),
array('user_id' => 33, 'tmp_id' => 4),
array('user_id' => 33, 'tmp_id' => 5)
);
# $arr = array_intersect_key($arr, array_unique(array_map('serialize', $arr)));
$arr = array_intersect_key($arr, array_unique(array_map(function ($el) {
return $el['user_id'];
}, $arr)));
//result:
array
0 =>
array
'user_id' => int 33
'tmp_id' => int 3
Во-первых, он не выполняет ненужную сериализацию. Во-вторых, иногда атрибуты могут быть разными, даже если id одинаковый.
Я столкнулся с этим API Google Адресов. Я сочетал результаты нескольких запросов с разными типами объектов (думаю теги). Но у меня есть дубликаты, так как объект может быть помещен в несколько категорий (типов). И метод с serialize
не работал, так как attrs были разными, а именно photo_reference
и reference
. Вероятно, это похоже на временные идентификаторы.
Ответ 4
array_unique deosn't работает рекурсивно, поэтому он просто думает: "Это все Array
s, пусть убивают всех, кроме одного... здесь мы идем!"
Ответ 5
Быстрый ответ (TL; DR)
- Отличительные значения могут быть извлечены из массива PHP ассоциативных атрибутов, используя foreach
- Это упрощенный подход
Подробный ответ
Контекст
- PHP 5.3
- Массив PHP ассоциативных массивов (переменная составных данных табуляции)
- Альтернативное имя для этой составной переменной - ArrayOfDictionary (AOD)
Проблема
- Сценарий: DeveloperMarsher имеет встроенную составную переменную PHP
- DeveloperMarsher хочет извлечь отдельные значения в определенную пару имя-значение
- В приведенном ниже примере DeveloperMarsher хочет получить строки для каждой отдельной пары
fname
name-value
Решение
-
example01;; DeveloperMarsher начинается с переменной данных табуляции, которая выглядит следующим образом:
$aodtable = json_decode('[
{
"fname": "homer"
,"lname": "simpson"
},
{
"fname": "homer"
,"lname": "jackson"
},
{
"fname": "homer"
,"lname": "johnson"
},
{
"fname": "bart"
,"lname": "johnson"
},
{
"fname": "bart"
,"lname": "jackson"
},
{
"fname": "bart"
,"lname": "simpson"
},
{
"fname": "fred"
,"lname": "flintstone"
}
]',true);
-
example01;; DeveloperMarsher может извлекать различные значения с помощью цикла foreach, который отслеживает увиденные значения
$sgfield = 'fname';
$bgnocase = true;
//
$targfield = $sgfield;
$ddseen = Array();
$vout = Array();
foreach ($aodtable as $datarow) {
if( (boolean) $bgnocase == true ){ @$datarow[$targfield] = @strtolower($datarow[$targfield]); }
if( (string) @$ddseen[ $datarow[$targfield] ] == '' ){
$rowout = array_intersect_key($datarow, array_flip(array_keys($datarow)));
$ddseen[ $datarow[$targfield] ] = $datarow[$targfield];
$vout[] = Array( $rowout );
}
}
//;;
print var_export( $vout, true );
Результат вывода
array (
0 =>
array (
0 =>
array (
'fname' => 'homer',
'lname' => 'simpson',
),
),
1 =>
array (
0 =>
array (
'fname' => 'bart',
'lname' => 'johnson',
),
),
2 =>
array (
0 =>
array (
'fname' => 'fred',
'lname' => 'flintstone',
),
),
)
Ловушки
- Это решение не объединяется в поля, которые не являются частью операции DISTINCT.
- Произвольные пары имени и имени возвращаются из произвольно выбранных строк
- Произвольный порядок сортировки вывода
- Произвольное обращение с почтовым ящиком (является ли капитал A отличным от нижнего регистра a?)
См. также
- php array_intersect_key
- php array_flip