Как мне использовать array_unique для массива массивов?

StackOverflow https://stackoverflow.com/questions/2561248

  •  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

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

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

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

  3. 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;
}

Разве это не помогает?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top