Как использовать 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 работает не так, как ожидалось?
5 ответов
потому что array_unique
сравнивает элементы с помощью сравнения строк. От docs:
Примечание: рассматриваются два элемента равны, если и только если (string) $elem1 === (строка) $elem2. In words: когда строковое представление одно и то же. Будет использован первый элемент.
строковое представление массива-это просто слово 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 (поскольку ключи исходного массива сохранены) и pull они из твоего первоисточник матрица.
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
во-первых, он не делает ненужных сериализации. Во-вторых, иногда атрибуты могут отличаться, даже если id один и тот же.
я столкнулся с Google Places API. Я комбинировал результаты нескольких запросов с различными типами объектов (думаю, теги). Но я получил дубликаты, так как объект может быть помещен в несколько категорий (типов). И метод с serialize
не работы, поскольку у attrs были разные, а именно:photo_reference
и reference
. Возможно, это временные удостоверения личности.
array_unique deosn не работает рекурсивно, поэтому он просто думает: "это все Array
s, давайте убьем всех, кроме одного... поехали!"
быстрый ответ (TL;DR)
- различные значения могут быть извлечены из массива PHP AssociativeArrays с помощью foreach
- это упрощенный подход
Подробный Ответ!--5-->
контекст
- PHP 5.3
- PHP массив AssociativeArrays (tabluar составная переменная данных)
- альтернативным именем для этой составной переменной является ArrayOfDictionary (AOD)
-
сценарий: DeveloperMarsher имеет табличную составную переменную PHP
- DeveloperMarsher хочет извлечь отдельные значения на конкретной паре имя-значение
- в приведенном ниже примере DeveloperMarsher хочет получить строки для каждого отдельного
fname
пары имя-значение
решение
-
example01 ;; DeveloperMarsher начинает с переменной данных tabluar, которая выглядит следующим образом
$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', ), ), )
подводные камни
- это решение не агрегируется на полях, которые не являются частью отдельной операции
- произвольные пары имя-значение возвращаются из произвольно выбранных отдельные ряды
- произвольный порядок сортировки вывода
- произвольная обработка буквенного регистра (является ли капитал отличным от нижнего регистра a ?)
см. также
- php array_intersect_key
- php array_flip