Como uso array_unique em um array de arrays?
-
23-09-2019 - |
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?
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:
Cada item da matriz é serializado. Isso será único com base no conteúdo da matriz.
Os resultados disso são executados
array_unique
, então apenas matrizes com assinaturas exclusivas são deixadas.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 Array
S, 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?