Как использовать array_unique для массива массивов? - PullRequest
18 голосов
/ 01 апреля 2010

у меня есть массив

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 не работает должным образом?

Ответы [ 6 ]

63 голосов
/ 01 апреля 2010

Это потому, что 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

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

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

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

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

3 голосов
/ 01 апреля 2010

array_unique() поддерживает только многомерные массивы в PHP 5.2.9 и выше.

Вместо этого вы можете создать хэш массива и проверить его на уникальность.

$hashes = array(); 

foreach($array as $val) { 
    $hashes[md5(serialize($val))] = $val; 
} 

array_unique($hashes);
2 голосов
/ 07 декабря 2016

Вот улучшенная версия ответа @ 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

Во-первых, он не выполняет ненужную сериализацию. Во-вторых, иногда атрибуты могут отличаться, даже если идентификатор один и тот же.

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

1 голос
/ 01 апреля 2010

array_unique не работает рекурсивно, поэтому он просто думает, что "это все Array s, давайте убьем всех, кроме одного ... вот так!"

0 голосов
/ 08 ноября 2018
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;
}

Разве это не делает трюк?

0 голосов
/ 28 февраля 2017

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

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

Подробный ответ

Контекст

  • PHP 5.3
  • PHP Массив AssociativeArrays (табулированная переменная составных данных)
  • Альтернативное имя для этой составной переменной - 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": "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
...