Как мне использовать array_unique для массива массивов?
-
23-09-2019 - |
Вопрос
У меня есть массив
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 работает не так, как ожидалось?
Решение
Это потому, что array_unique
сравнивает элементы с помощью сравнения строк.Из самого Документы:
Примечание:Два элемента считаются равными тогда и только тогда, когда (строка) $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
возьмет ключи уникальных элементов из функции map / unique (поскольку ключи исходного массива сохранены) и извлекет их из вашего исходного массива.
Другие советы
array_unique()
поддерживает многомерные массивы только в PHP 5.2.9 и выше.
Вместо этого вы можете создать хеш массива и проверить его уникальность.
$hashes = array();
foreach($array as $val) {
$hashes[md5(serialize($val))] = $val;
}
array_unique($hashes);
Вот улучшенная версия Ответ @ryeguy:
<?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
Во-первых, он не выполняет ненужную сериализацию.Во-вторых, иногда атрибуты могут различаться, даже если идентификатор один и тот же.
Я столкнулся с этим с API Google Адресов.Я объединял результаты нескольких запросов с объектами разных типов (например, тегами).Но у меня появились дубликаты, так как объект можно отнести к нескольким категориям (типам).И метод с serialize
не сработало, так как атрибуты были разные, а именно: photo_reference
и reference
.Наверное это что-то вроде временных идентификаторов.
array_unique не работает рекурсивно, поэтому он просто думает: «Это все Array
х, давай убьем всех, кроме одного...вот так!"
Быстрый ответ (TL;DR)
- Различные значения могут быть извлечены из PHP-массива AssociativeArrays с помощью foreach.
- Это упрощенный подход
Подробный ответ
Контекст
- PHP 5.3
- PHP-массив AssociativeArrays (табличная составная переменная данных)
- Альтернативное имя этой составной переменной — ArrayOfDictionary (AOD).
Проблема
- Сценарий: DeveloperMarsher имеет табличную составную переменную PHP.
- DeveloperMarsher хочет извлечь отдельные значения из конкретной пары имя-значение.
- В приведенном ниже примере DeveloperMarsher хочет получить строки для каждого отдельного
fname
пара имя-значение
Решение
пример01 ;;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);
пример01 ;;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
function array_unique_recursive($array)
{
$array = array_unique($array, SORT_REGULAR);
foreach ($array as $key => $elem) {
if (is_array($elem)) {
$array[$key] = array_unique_recursive($elem);
}
}
return $array;
}
Разве это не помогает?