Come rimuovere i valori duplicati da un array multidimensionale in PHP


306

Come posso rimuovere valori duplicati da un array multidimensionale in PHP?

Matrice di esempio:

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
    )

)

Risposte:


637

Ecco un altro modo. Nessuna variabile intermedia viene salvata.

Abbiamo usato questo per de-duplicare i risultati da una varietà di query sovrapposte.

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

23
A causa della non serializzazione, questo è sempre più lento quanto più grande e complessa è la matrice. C'è un motivo per cui ho usato array_intersect_key (sei mesi prima di questa risposta).
OIS,

11
@OIS lo ha appena testato, aveva un refuso ma funziona .. grazie amico !: $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array)));
trevorkavanaugh,

3
se vuoi che l'indice sia continuo, usa array_values ​​cioè $ input = array_values ​​(array_map ("unserialize", array_unique (array_map ("serialize", $ input))));
lbsweek,

4
Oggi probabilmente sceglieresti json_encode e json_decode invece della serializzazione PHP. dovrebbe avere vantaggi per i valori forniti e non dovresti imbatterti in dettagli di serializzazione PHP che serializzano / non serializzano le navi e molto probabilmente sono indesiderate.
Hacre,

2
Attenzione che serialize(array('a' => '1', 'b' => '1'))è diverso da serialize(array('b' => '1', 'a' => '1')). Questa opzione fallirà per le matrici usate come setso (hash)maps.
Andras Gyomrey,

240

Dalla 5.2.9 puoi usare array_unique()se usi la SORT_REGULARbandiera in questo modo:

array_unique($array, SORT_REGULAR);

Questo rende la funzione confronta gli elementi per l'uguaglianza come se $a == $bfossero usati, il che è perfetto per il tuo caso.

Produzione

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

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

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

)

Tieni presente, tuttavia, che la documentazione afferma:

array_unique() non è progettato per funzionare su array multidimensionali.


2
Immagino che questa sia una soluzione più rapida e più chiara di quella accettata! votiamo per questo! :) Hmmm sul sito php possiamo vedere che non è così veloce, come pensavo ...
Andron,

4
Strano che usare il flag SORT_REGULAR non funzioni per me, per rimuovere matrici duplicate.
Stefan,

4
@Stefan Hai ragione; non sembra dare i risultati corretti, ma è probabilmente un bug perché funziona con PHP 7 = /
Ja͢ck

4
Anche questo sembra funzionare nel mio caso, ma qualcun altro è infastidito da questa nota nel documento array_unique ()? php.net/manual/it/…
Arleigh Hix

2
@Jack Hai ragione, questo è un bug a partire da PHP 5.6.23: eval.in/645675 ma è stato corretto a partire da PHP 7.0.8: eval.in/645676
Zack Morris,

63

Ho avuto un problema simile ma ho trovato una soluzione funzionante al 100% per questo.

<?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
Questo risponde a una domanda diversa. Vedi qui: stackoverflow.com/questions/4585208/…
OIS

Ottima funzione! e nel caso tu abbia a che fare con oggetti: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox

35

Un altro modo. Conserverà anche le chiavi.

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

Per array di grandi dimensioni, questo metodo è spesso almeno il 50% più veloce della risposta accettata.
Lorien Brune,

21

I commenti degli utenti sulla documentazione array_unique () hanno molte soluzioni a questo. Eccone uno:

kenrbnsn at rbnsn dot com
27-set-2005 12:09

Ancora un altro Array_Unique per array multi-demensioned. L'ho testato solo su array a due dimensioni, ma probabilmente potrebbe essere generalizzato per altro o fatto ricorrere alla ricorsione.

Questa funzione utilizza le funzioni serialize, array_unique e unserialize per eseguire il lavoro.


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

Questo è da http://ca3.php.net/manual/en/function.array-unique.php#57202 .


18

Se "rimuovi duplicati" significa "rimuovi duplicati, ma lasciane uno lì", una soluzione potrebbe essere quella di applicare prima array_unique(...)la "colonna identificatore" e poi rimuovere nell'array originale tutte le chiavi, che sono state rimosse dall'array di colonne :

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

Il risultato è:

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

Ciò rimuoverà i nomi duplicati dall'array. unico per chiave


Assicurati che $arrayle chiavi inizino da "0". È possibile che $arrayle chiavi inizino da un altro numero se $arrayè il risultato di una precedente manipolazione dell'array. Utilizzare array_valuesper ripristinare i tasti su "0"
stevevance


4

Usa solo l'opzione SORT_REGULAR come secondo parametro.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR funziona solo in PHP 7 perché PHP 5 ha un bug (sebbene @ r3wt sia corretto secondo la documentazione), vedi il mio commento nella risposta per un esempio eseguibile stackoverflow.com/questions/307674/…
Zack Morris,

Perché dovresti aggiungere questo? E 'lo stesso di questa risposta, che è più di un anno più vecchio di vostra: stackoverflow.com/a/18373723/870729
random_user_name

3

se hai bisogno di eliminare duplicati su tasti specifici, come un id mysqli, ecco una semplice funzione

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

Punti bonus Puoi passare una serie di chiavi e aggiungere una foreach esterna, ma sarà 2 volte più lenta per ogni chiave aggiuntiva.


3

Di seguito è riportato un modo molto semplice e logico per creare un array multidimensionale come unico,

Se hai array come questo:

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

usare foreachper risolvere questo:

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

ti darà il seguente risultato:

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

e se vuoi riorganizzare l'ordine delle chiavi,

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

Questa operazione ti darà valori chiave organizzati come questo:

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

Spero che questo cancella tutto.


2

se hai un array come questo:

(utenti è il nome dell'array)

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

e vuoi eliminare i duplicati ... quindi:

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

può essere una soluzione: P


1

Una soluzione di facile lettura, probabilmente non la più efficiente:

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

Come dicono le persone array_unique()è molto lento, ecco uno snippet che uso per un array multidimensionale di livello.

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

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

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

Il primo utente di riferimento ha contribuito alla nota della pagina delle array_unique() funzioni in php.net


Anuj, potresti per favore modificare la tua risposta? C'è un bug. Dovrebbe finire $output = array_map('unserialize', array_keys($result));
KeyboardSmasher

@keyboardSmasher grazie per il tuo contributo. Ho apportato le modifiche e ora funziona. :)
Anuj,

1

Molte persone mi hanno chiesto come realizzare un array multidimensionale unico. Ho preso riferimento al tuo commento e mi aiuta.

Prima di tutto, grazie a @jeromegamez @daveilers per la tua soluzione. Ma ogni volta che ho dato la risposta, mi hanno chiesto come funziona questa "serializzazione" e "non serializzazione". Ecco perché voglio condividere la ragione di questo con te in modo che possa aiutare più persone a capire il concetto alla base di questo.

Sto spiegando perché usiamo "serializzare" e "non serializzare" nei passaggi:

Passaggio 1: convertire l'array multidimensionale in array monodimensionale

Per convertire l'array multidimensionale in un array monodimensionale, generare innanzitutto una rappresentazione a flusso di byte di tutti gli elementi (compresi gli array nidificati) all'interno dell'array. la funzione serialize () può generare una rappresentazione di flusso di byte di un valore. Per generare una rappresentazione di flusso di byte di tutti gli elementi, chiamare la funzione serialize () all'interno della funzione array_map () come funzione di callback. Il risultato sarà un array monodimensionale, indipendentemente da quanti livelli ha l'array multidimensionale.

Passaggio 2: rendere unici i valori

Per rendere unico questo array monodimensionale, utilizzare la funzione array_unique ().

Passaggio 3: ripristinarlo nella matrice multidimensionale

Sebbene l'array sia ora univoco, i valori assomigliano alla rappresentazione del flusso di byte. Per ripristinare l'array multidimensionale, utilizzare la funzione unserialize ().

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

Grazie ancora per tutto questo.


0

Un'alternativa alla serializzazione e unica

$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

Se hai un array come questo

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

e vuoi ottenere array in questo modo:

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 seguente codice può aiutare

    $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

Ho riflettuto molto su questo problema e ho determinato che la soluzione ottimale dovrebbe seguire due regole.

  1. Per la scalabilità, modificare l'array in posizione; nessuna copia su un nuovo array
  2. Per le prestazioni, ogni confronto deve essere effettuato una sola volta

Con questo in mente e date tutte le stranezze di PHP, di seguito è la soluzione che mi è venuta in mente. A differenza di alcune delle altre risposte, ha la capacità di rimuovere elementi in base a qualsiasi chiave (e) desiderata. L'array di input dovrebbe essere costituito da tasti numerici.

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

L'unico inconveniente è che le chiavi non sono in ordine al completamento dell'iterazione. Questo non è un problema se successivamente si utilizzano solo cicli foreach, ma se è necessario utilizzare un ciclo for, è possibile inserire $input = array_values($input);quanto segue per rinumerare le chiavi.


0

Basato sulla risposta contrassegnata come corretta, aggiungendo la mia risposta. Piccolo codice aggiunto solo per ripristinare gli indici-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.