Как использовать 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 работает не так, как ожидалось?

Это потому, что array_unique сравнивает элементы, используя сравнение строк. Из документов :

Примечание. Два элемента считаются равными тогда и только тогда, когда (строка) $ elem1 === (string) $ 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 

Вот как это работает:

  1. Каждый элемент массива сериализуется. Это будет уникально на основе содержимого массива.

  2. Результаты этого запускаются через array_unique , поэтому остаются только массивы с уникальными сигнатурами.

  3. array_intersect_key возьмет ключи уникальных элементов из карты / уникальной функции (поскольку ключи исходного массива сохранены) и вытащите их из исходного исходного массива.

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 одинаковый.

Я столкнулся с этим с API Google Адресов . Я сочетал результаты нескольких запросов с разными типами объектов (думаю теги). Но у меня есть дубликаты, так как объект может быть помещен в несколько категорий (типов). И метод с serialize не работал, поскольку attrs были разными, а именно: photo_reference и reference . Вероятно, это похоже на временные идентификаторы.

array_unique deosn't работает рекурсивно, поэтому он просто думает: «Это все Array , давайте убьем всех, кроме одного … здесь мы идем!»

Быстрый ответ (TL; DR)

  • Отдельные значения могут быть извлечены из массива PHP ассоциативных атрибутов, используя foreach
  • Это упрощенный подход

Детальный ответ

контекст

  • PHP 5.3
  • PHP-массив ассоциативных массивов (переменная составных данных табуляции)
  • Альтернативным именем для этой составной переменной является ArrayOfDictionary (AOD)

проблема

  • Сценарий: DeveloperMarsher имеет табличную составную переменную PHP
    • DeveloperMarsher хочет извлечь отдельные значения для определенной пары имя-значение
    • В приведенном ниже примере DeveloperMarsher хочет получить строки для каждой отдельной пары имя-значение fname

Решение

  • 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": "кремневый камень"
     }
     ]',правда);
    
  • example01 ;; DeveloperMarsher может извлекать отдельные значения с помощью цикла foreach, который отслеживает видимые значения

     $ sgfield = 'fname';
     $ bgnocase = true;
    
     //
     $ targfield = $ sgfield;
     $ ddseen = Array ();
     $ vout = Array ();
     foreach ($ aodtable как $ 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 [] = Массив ($ rowout);
     }
     }
     // ;;
    
     print var_export ($ vout, true);
    

Результат вывода

 массив (
   0 =>
   массив (
     0 =>
     массив (
       'fname' => 'homer',
       'lname' => 'simpson',
     ),
   ),
   1 =>
   массив (
     0 =>
     массив (
       'fname' => 'bart',
       'lname' => 'johnson',
     ),
   ),
   2 =>
   массив (
     0 =>
     массив (
       'fname' => 'fred',
       'lname' => 'flintstone',
     ),
   ),
 )

Ловушки

  • Это решение не объединяется в поля, которые не являются частью операции DISTINCT
  • Произвольные пары имя-значение возвращаются из произвольно выбранных строк
  • Произвольный порядок сортировки
  • Произвольное обращение с почтовым ящиком (является ли капитал A отличным от нижнего регистра a?)

Смотрите также

  • php array_intersect_key
  • php array_flip