Cómo eliminar valores duplicados de una matriz multidimensional en PHP


306

¿Cómo puedo eliminar valores duplicados de una matriz multidimensional en PHP?

Matriz de ejemplo:

Array
(
    [0] => Array
    (
        [0] => abc
        [1] => def
    )

    [1] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [2] => Array
    (
        [0] => mno
        [1] => pql
    )

    [3] => Array
    (
        [0] => abc
        [1] => def
    )

    [4] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [5] => Array
    (
        [0] => mno
        [1] => pql
    )

)

Respuestas:


637

Aquí hay otra manera. No se guardan variables intermedias.

Usamos esto para deduplicar resultados de una variedad de consultas superpuestas.

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

23
Debido a la falta de serialización, esto es cada vez más lento cuanto más grande y complejo es el arreglo. Hay una razón por la que usé array_intersect_key (medio año antes de esta respuesta).
OIS

11
@OIS lo acabo de probar, tenía un error tipográfico pero funciona ... ¡gracias amigo !: $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array)));
trevorkavanaugh

3
si desea que el índice sea continuo, use valores_arrays, es decir, $ input = valores_arrays (array_map ("unserialize", array_unique (array_map ("serialize", $ input))));
lbsweek

44
Hoy en día, probablemente optaría por json_encode y json_decode en lugar de la serialización PHP. debería tener beneficios para los valores proporcionados y no se encontrará con detalles de serialización de PHP con los que serializar / deserializar envíos es muy probable que no sean deseados.
Hakre

2
Cuidado que serialize(array('a' => '1', 'b' => '1'))es diferente de serialize(array('b' => '1', 'a' => '1')). Esta opción fallará para las matrices utilizadas como setso (hash)maps.
Andras Gyomrey

240

Desde 5.2.9 puede usar array_unique()si usa la SORT_REGULARbandera de esta manera:

array_unique($array, SORT_REGULAR);

Esto hace que la función compare elementos para la igualdad como si $a == $b se estuvieran utilizando, lo cual es perfecto para su caso.

Salida

Array
(
    [0] => Array
        (
            [0] => abc
            [1] => def
        )

    [1] => Array
        (
            [0] => ghi
            [1] => jkl
        )

    [2] => Array
        (
            [0] => mno
            [1] => pql
        )

)

Sin embargo, tenga en cuenta que la documentación dice:

array_unique() no está destinado a funcionar en matrices multidimensionales.


2
¡Supongo que esta es una solución más rápida y más clara que la aceptada! ¡votemos por este! :) Hmmm en el sitio php podemos ver que no es tan rápido, como pensé ...
Andron

44
Es extraño que usar el indicador SORT_REGULAR simplemente no funcione para mí, para eliminar matrices duplicadas.
Stefan

44
@Stefan Tienes razón; no parece dar los resultados correctos, pero probablemente sea un error porque funciona con PHP 7 = /
Ja͢ck

44
Esto también parece funcionar en mi caso, pero ¿alguien más está molesto por esta nota en el documento array_unique ()? php.net/manual/en/…
Arleigh Hix

2
@Jack Tienes razón, este es un error a partir de PHP 5.6.23: eval.in/645675 pero se corrigió a partir de PHP 7.0.8: eval.in/645676
Zack Morris

63

Tuve un problema similar pero encontré una solución 100% funcional.

<?php
    function super_unique($array,$key)
    {
       $temp_array = [];
       foreach ($array as &$v) {
           if (!isset($temp_array[$v[$key]]))
           $temp_array[$v[$key]] =& $v;
       }
       $array = array_values($temp_array);
       return $array;

    }


$arr="";
$arr[0]['id']=0;
$arr[0]['titel']="ABC";
$arr[1]['id']=1;
$arr[1]['titel']="DEF";
$arr[2]['id']=2;
$arr[2]['titel']="ABC";
$arr[3]['id']=3;
$arr[3]['titel']="XYZ";

echo "<pre>";
print_r($arr);
echo "unique*********************<br/>";
print_r(super_unique($arr,'titel'));

?>

1
Esto responde a una pregunta diferente. Ver aquí: stackoverflow.com/questions/4585208/…
OIS

Gran función! y en caso de que esté tratando con objetos: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox

35

De otra manera. Conservará las llaves también.

function array_unique_multidimensional($input)
{
    $serialized = array_map('serialize', $input);
    $unique = array_unique($serialized);
    return array_intersect_key($input, $unique);
}

Para matrices grandes, este método suele ser al menos un 50% más rápido que la respuesta aceptada.
Lorien Brune

21

Los comentarios de los usuarios sobre la documentación de array_unique () tienen muchas soluciones para esto. Aqui esta uno de ellos:

kenrbnsn en rbnsn dot com
27-sep-2005 12:09

Sin embargo, otro Array_Unique para matrices multi-demensionadas. Solo he probado esto en matrices de dos dimensiones, pero probablemente podría generalizarse para más, o hacer que se use la recursividad.

Esta función utiliza las funciones serializar, array_unique y deserializar para hacer el trabajo.


function multi_unique($array) {
    foreach ($array as $k=>$na)
        $new[$k] = serialize($na);
    $uniq = array_unique($new);
    foreach($uniq as $k=>$ser)
        $new1[$k] = unserialize($ser);
    return ($new1);
}

Esto es de http://ca3.php.net/manual/en/function.array-unique.php#57202 .


18

Si "eliminar duplicados" significa "eliminar duplicados, pero deje uno allí", una solución podría ser aplicar array_unique(...)primero en la "columna de identificación" y luego eliminar en la matriz original todas las claves que se han eliminado de la matriz de columnas :

$array = [
    [
        'id' => '123',
        'foo' => 'aaa',
        'bar' => 'bbb'
    ],
    [
        'id' => '123',
        'foo' => 'ccc',
        'bar' => 'ddd'
    ],
    [
        'id' => '567',
        'foo' => 'eee',
        'bar' => 'fff'
    ]
];

$ids = array_column($array, 'id');
$ids = array_unique($ids);
$array = array_filter($array, function ($key, $value) use ($ids) {
    return in_array($value, array_keys($ids));
}, ARRAY_FILTER_USE_BOTH);

El resultado es:

Array
(
    [0] => Array
        (
            [id] => 123
            [foo] => aaa
            [bar] => bbb
        )

    [2] => Array
        (
            [id] => 567
            [foo] => eee
            [bar] => fff
        )

)

18
Array
(
    [0] => Array
        (
            [id] => 1
            [name] => john
        )

    [1] => Array
        (
            [id] => 2
            [name] => smith
        )

    [2] => Array
        (
            [id] => 3
            [name] => john
        )

    [3] => Array
        (
            [id] => 4
            [name] => robert
        )

)

$temp = array_unique(array_column($array, 'name'));
$unique_arr = array_intersect_key($array, $temp);

Esto eliminará los nombres duplicados de la matriz. único por clave


Asegúrese de que $arraylas teclas comiencen en "0". Es posible que $arraylas teclas comiencen en otro número si $arrayes el resultado de una manipulación previa de la matriz. Use array_valuespara restablecer las teclas de nuevo a "0"
stevevance


4

Simplemente use la opción SORT_REGULAR como segundo parámetro.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR solo funciona en PHP 7 porque PHP 5 tiene un error (aunque @ r3wt es correcto según la documentación), vea mi comentario en la respuesta para un ejemplo ejecutable stackoverflow.com/questions/307674/…
Zack Morris

¿Por qué agregarías esto? Es lo mismo que esta respuesta, que es más de un año mayor que la suya: stackoverflow.com/a/18373723/870729
random_user_name el

3

si necesita eliminar duplicados en claves específicas, como una identificación de mysqli, aquí hay una función simple

function search_array_compact($data,$key){
    $compact = [];
    foreach($data as $row){
        if(!in_array($row[$key],$compact)){
            $compact[] = $row;
        }
    }
    return $compact;
}

Puntos de bonificación Puede pasar una serie de claves y agregar un foreach externo, pero será 2 veces más lento por clave adicional.


3

Una forma muy fácil y lógica de crear una matriz multidimensional única es la siguiente:

Si tienes una matriz como esta:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value1
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value1
            [3] => Value3
            [4] => Value4
        )
)

utilizar foreachpara resolver esto:

foreach($array as $k=>$v){
    $unique=array_unique($v);
    $array[$k]=$unique;
}

te dará el siguiente resultado:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [3] => Value3
            [4] => Value4
        )
)

y si quieres reorganizar el orden de las teclas,

foreach($array as $k=>$v){
    $unique= array_values(array_unique($v));
    $array[$k]=$unique;
}

Esta operación le dará valores clave organizados como este:

Array
(
    [Key1] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
        )
    [Key2] => Array
        (
            [0] => Value1
            [1] => Value2
            [2] => Value3
            [3] => Value4
        )
)

Espero que esto aclare todo.


2

si tienes una matriz como esta:

(usuarios es el nombre de la matriz)

Array=>
 [0] => (array)
   'user' => 'john'
   'age' => '23'
 [1] => (array)
  'user' => 'jane'
  'age' => '20'
 [2]=> (array)
  'user' => 'john'
  'age' => '23'

y quieres eliminar duplicados ... entonces:

$serialized = array();
for ($i=0; $i < sizeof($users); $i++) { 
  $test = in_array($users['user'], $serialized);
    if ($test == false) {
      $serialized[] = $users['user'];
    }
 }

puede ser una solución: P


1

Una solución fácil de leer, probablemente no la más eficiente:

function arrayUnique($myArray){
    if(!is_array($myArray))
        return $myArray;

    foreach ($myArray as &$myvalue){
        $myvalue=serialize($myvalue);
    }

    $myArray=array_unique($myArray);

    foreach ($myArray as &$myvalue){
        $myvalue=unserialize($myvalue);
    }

    return $myArray;

} 

1

Como la gente dice que array_unique()es muy lento, aquí hay un fragmento que uso para una matriz multidimensional de un nivel.

$serialized_array = array_map("serialize", $input);

foreach ($serialized_array as $key => $val) {
     $result[$val] = true;
}

$output = array_map("unserialize", (array_keys($result)));

Referencia del primer usuario contribuido nota de la página de array_unique() funciones en php.net


Anuj, ¿podrías editar tu respuesta? Hay un error Debería terminar $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasher gracias por tu aporte. Hice los cambios y ahora funciona. :)
Anuj

1

Mucha gente me preguntó cómo hacer una matriz multidimensional única. He tomado referencia de tu comentario y me ayuda.

En primer lugar, gracias a @jeromegamez @daveilers por su solución. Pero cada vez que respondía, me preguntaban cómo funciona este 'serializar' y 'no serializar'. Es por eso que quiero compartir la razón de esto con usted para que ayude a más personas a comprender el concepto detrás de esto.

Estoy explicando por qué usamos 'serializar' y 'deserializar' en pasos:

Paso 1: Convierta la matriz multidimensional en una matriz unidimensional

Para convertir la matriz multidimensional en una matriz unidimensional, primero genere una representación de flujo de bytes de todos los elementos (incluidas las matrices anidadas) dentro de la matriz. La función serialize () puede generar una representación de flujo de bytes de un valor. Para generar una representación de flujo de bytes de todos los elementos, llame a la función serialize () dentro de la función array_map () como una función de devolución de llamada. El resultado será una matriz unidimensional sin importar cuántos niveles tenga la matriz multidimensional.

Paso 2: haga que los valores sean únicos

Para hacer que esta matriz unidimensional sea única, use la función array_unique ().

Paso 3: revertirlo a la matriz multidimensional

Aunque la matriz ahora es única, los valores parecen una representación de flujo de bytes. Para revertirlo a la matriz multidimensional, use la función unserialize ().

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));

Gracias de nuevo por todo esto.


0

Una alternativa para serializar y única

$test = [
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
    ['abc','def'],
    ['ghi','jkl'],
    ['mno','pql'],
];

$result = array_reduce(
    $test,
    function($carry,$item){
        if(!in_array($item,$carry)) {
            array_push($carry,$item);
        }
        return $carry;
    },
    []
);

var_dump($result);

/*
 php unique.php
array(3) {
    [0] =>
        array(2) {
            [0] =>
                string(3) "abc"
            [1] =>
                string(3) "def"
        }
    [1] =>
        array(2) {
            [0] =>
                string(3) "ghi"
            [1] =>
                string(3) "jkl"
        }
    [2] =>
        array(2) {
              [0] =>
                  string(3) "mno"
              [1] =>
                  string(3) "pql"
        }
}

* /


0

Si tienes una matriz como esta

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => b
),
[3] => array
(
    [subject] => d
    [object] => c
),
[4] => array
(
    [subject] => c
    [object] => a
),
[5] => array
(
    [subject] => c
    [object] => d
)
)

y quieres obtener matrices como esta:

data = array
(
[0] => array
(
    [subject] => a
    [object] => c
),
[1] => array
(
    [subject] => b
    [object] => d
),
[2] => array
(
    [subject] => d
    [object] => c
)
)

o

data = array
(
[0] => array
(
    [subject] => d
    [object] => b
),
[1] => array
(
    [subject] => c
    [object] => a
),
[2] => array
(
    [subject] => c
    [object] => d
)
)

un siguiente código puede ayudar

    $data1 = array();
    $data1 = $data;
    for($q=0;$q<count($data);$q++)
    {
            for($p=0;$p<count($data1);$p++)
            {
                    if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"]))
                    {
                            $data1[$p]["subject"] = $data[$q]["subject"];
                            $data1[$p]["object"] = $data[$q]["object"];
                    }
            }
    }
    $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1))));
    $data = $data1;

0

He pensado mucho en este problema y he determinado que la solución óptima debe seguir dos reglas.

  1. Para la escalabilidad, modifique la matriz en su lugar; sin copiar a una nueva matriz
  2. Para el rendimiento, cada comparación debe hacerse solo una vez

Con eso en mente y teniendo en cuenta todas las peculiaridades de PHP, a continuación se muestra la solución que se me ocurrió. A diferencia de algunas de las otras respuestas, tiene la capacidad de eliminar elementos en función de las claves que desee. Se espera que la matriz de entrada sean teclas numéricas.

$count_array = count($input);
for ($i = 0; $i < $count_array; $i++) {
    if (isset($input[$i])) {
        for ($j = $i+1; $j < $count_array; $j++) {
            if (isset($input[$j])) {
                //this is where you do your comparison for dupes
                if ($input[$i]['checksum'] == $input[$j]['checksum']) {
                    unset($input[$j]);
                }
            }
        }
    }
}

El único inconveniente es que las teclas no están en orden cuando se completa la iteración. Esto no es un problema si posteriormente usa solo bucles foreach, pero si necesita usar un bucle for, puede colocar $input = array_values($input);después de lo anterior para volver a numerar las teclas.


0

Basado en la respuesta marcada como correcta, agregando mi respuesta. Pequeño código agregado solo para restablecer los índices

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.