Pergunta

Eu tenho uma matriz

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
    )

)

Como você pode ver, a chave 0 é igual a 1, 3 e 4.E a chave 2 é diferente de todas elas.

Ao executar a função array_unique neles, a única coisa que resta é

Array (
[0] => Array
    (
        [0] => 33
        [user_id] => 33
        [1] => 3
        [frame_id] => 3
    )
)

Alguma idéia de por que array_unique não está funcionando conforme o esperado?

Foi útil?

Solução

É porque array_unique compara itens usando uma comparação de string. De documentos:

Nota: Dois elementos são considerados iguais se e somente se (string) $ elem1 === (String) $ elem2. Nas palavras: quando a representação da string é a mesma. O primeiro elemento será usado.

A representação da string de uma matriz é simplesmente a palavra Array, não importa qual seja o seu conteúdo.

Você pode fazer o que deseja fazer usando o seguinte:

$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

Veja como funciona:

  1. Cada item da matriz é serializado. Isso será único com base no conteúdo da matriz.

  2. Os resultados disso são executados array_unique, então apenas matrizes com assinaturas exclusivas são deixadas.

  3. array_intersect_key Pegará as chaves dos itens exclusivos da função MAP/exclusiva (pois as teclas da matriz de origem são preservadas) e as retirarão da sua matriz de origem original.

Outras dicas

array_unique() Suporta apenas matrizes multidimensionais no PHP 5.2.9 e superior.

Em vez disso, você pode criar um hash da matriz e verificá-lo para obter o único.

$hashes = array(); 

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

array_unique($hashes);

Aqui está uma versão aprimorada de @Ryeguy Resposta:

<?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

Primeiro, não faz serialização desnecessária. Segundo, às vezes os atributos podem ser diferentes, mesmo assim o ID é o mesmo.

Eu encontrei com isso com API do Google Places. Eu estava combinando resultados de várias solicitações com diferentes tipos de objetos (tags Think). Mas obtive duplicatas, pois um objeto pode ser colocado em várias categorias (tipos). E o método com serialize não funcionou, já que os attrs eram diferentes, a saber, photo_reference e reference. Provavelmente estes são como IDs temporários.

Array_unique deos não funciona recursivo, então apenas pensa "isso é tudo ArrayS, vamos matar tudo, exceto um ... aqui vamos nós! "

Resposta rápida (TL;DR)

  • Valores distintos podem ser extraídos do array PHP de AssociativeArrays usando foreach
  • Esta é uma abordagem simplista

Resposta detalhada

Contexto

  • PHP 5.3
  • PHP Array of AssociativeArrays (variável tabular de dados compostos)
  • O nome alternativo para esta variável composta é ArrayOfDictionary (AOD)

Problema

  • Cenário: DeveloperMarsher tem uma variável composta tabular PHP
    • DeveloperMarsher deseja extrair valores distintos em um par nome-valor específico
    • No exemplo abaixo, DeveloperMarsher deseja obter linhas para cada fname par nome-valor

Solução

  • exemplo01 ;;DeveloperMarsher começa com uma variável de dados tabluar semelhante a esta

    $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);
    
  • exemplo01 ;;DeveloperMarsher pode extrair valores distintos com um loop foreach que rastreia valores vistos

    $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 );
    

Resultado de saída

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',
    ),
  ),
)

Armadilhas

  • Esta solução não agrega campos que não fazem parte da operação DISTINCT
  • Pares nome-valor arbitrários são retornados de linhas distintas escolhidas arbitrariamente
  • Ordem de classificação arbitrária de saída
  • Tratamento arbitrário de letras maiúsculas (A maiúsculo é distinto de a minúsculo?)

Veja também

  • 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;
}

Isso não faz o truque?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top