Comment supprimer les valeurs en double d'un tableau multidimensionnel en PHP


306

Comment puis-je supprimer les valeurs en double d'un tableau multidimensionnel en PHP?

Exemple de tableau:

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
    )

)

Réponses:


637

Voici une autre façon. Aucune variable intermédiaire n'est enregistrée.

Nous l'avons utilisé pour dédoublonner les résultats d'une variété de requêtes qui se chevauchent.

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

23
En raison de la désérialisation, cela est de plus en plus lent et plus la baie est grande et complexe. Il y a une raison pour laquelle j'ai utilisé array_intersect_key (six mois avant cette réponse).
OIS du

11
@OIS vient juste de le tester, avait une faute de frappe mais ça marche .. merci mec!: $ No_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array))));
trevorkavanaugh

3
si vous voulez que l'index soit continu, utilisez array_values ​​ie $ input = array_values ​​(array_map ("unserialize", array_unique (array_map ("serialize", $ input))));
lbsweek

4
De nos jours, vous opteriez probablement pour json_encode et json_decode au lieu de la sérialisation PHP. devrait avoir des avantages pour les valeurs fournies et vous ne rencontrez pas les détails de sérialisation PHP qui sérialisent / désérialisent les navires avec et sont très probablement indésirables.
hakre

2
Attention, c'est serialize(array('a' => '1', 'b' => '1'))différent de serialize(array('b' => '1', 'a' => '1')). Cette option échouera pour les tableaux utilisés comme setsou (hash)maps.
Andras Gyomrey

240

Depuis 5.2.9, vous pouvez utiliser array_unique()si vous utilisez le SORT_REGULARdrapeau comme ceci:

array_unique($array, SORT_REGULAR);

Cela fait que la fonction compare les éléments pour l'égalité comme s'ils $a == $bétaient utilisés, ce qui est parfait pour votre cas.

Production

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

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

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

)

Gardez à l'esprit, cependant, que la documentation indique:

array_unique() n'est pas destiné à fonctionner sur des tableaux multidimensionnels.


2
Je suppose que c'est une solution plus rapide et plus claire que celle acceptée! laisse voter pour celui-ci! :) Hmmm sur le site php on peut voir que ce n'est pas si rapide, comme je le pensais ...
Andron

4
Étrange que l'utilisation de l'indicateur SORT_REGULAR ne fonctionne tout simplement pas pour moi, pour supprimer les tableaux en double.
Stefan

4
@Stefan Vous avez raison; il ne semble pas donner les bons résultats, mais c'est probablement un bug car il fonctionne avec PHP 7 = /
Ja͢ck

4
Cela semble également fonctionner dans mon cas, mais quelqu'un d'autre est-il gêné par cette note dans la doc array_unique ()? php.net/manual/en/…
Arleigh Hix

2
@Jack Vous avez raison, c'est un bogue à partir de PHP 5.6.23: eval.in/645675 mais il est corrigé à partir de PHP 7.0.8: eval.in/645676
Zack Morris

63

J'ai eu un problème similaire mais j'ai trouvé une solution 100% fonctionnelle.

<?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
Cela répond à une question différente. Voir ici: stackoverflow.com/questions/4585208/…
OIS

Grande fonction! et dans le cas où vous avez affaire à des objets: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox

35

Autrement. Préserve également les clés.

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

Pour les grands tableaux, cette méthode est souvent au moins 50% plus rapide que la réponse acceptée.
Lorien Brune

21

Les commentaires des utilisateurs sur la documentation array_unique () ont de nombreuses solutions à cela. Voici l'un d'entre eux:

kenrbnsn à rbnsn dot com
27-Sep-2005 12:09

Encore un autre Array_Unique pour les tableaux à plusieurs dimensions. Je n'ai testé cela que sur des tableaux à deux dimensions, mais il pourrait probablement être généralisé pour plus, ou fait pour utiliser la récursivité.

Cette fonction utilise les fonctions serialize, array_unique et unserialize pour effectuer le travail.


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

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


18

Si "supprimer les doublons" signifie "supprimer les doublons, mais en laisser un là", une solution pourrait être d'appliquer d'abord la array_unique(...)sur la "colonne d'identification" puis de supprimer dans le tableau d'origine toutes les clés qui ont été supprimées du tableau de colonnes. :

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

Le résultat est:

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

Cela supprimera les noms en double du tableau. unique par clé


Assurez-vous que $arrayles clés commencent à "0". Il est possible que $arrayles clés commencent à un autre nombre si elles $arrayrésultent d'une manipulation préalable de tableau. Utilisez array_valuespour réinitialiser les clés à "0"
stevevance


4

Utilisez simplement l'option SORT_REGULAR comme deuxième paramètre.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR ne fonctionne qu'en PHP 7 car PHP 5 a un bogue (bien que @ r3wt soit correct selon la documentation), voir mon commentaire dans la réponse pour un exemple exécutable stackoverflow.com/questions/307674/…
Zack Morris

Pourquoi voudriez-vous ajouter ceci? C'est la même chose que cette réponse, qui a plus d'un an de plus que la vôtre: stackoverflow.com/a/18373723/870729
random_user_name

3

si vous devez éliminer les doublons sur des clés spécifiques, comme un identifiant mysqli, voici une fonction simple

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

Points bonus Vous pouvez passer un tableau de clés et ajouter une foreach externe, mais ce sera 2x plus lent par clé supplémentaire.


3

Un moyen très simple et logique pour Unique un tableau multidimensionnel est le suivant,

Si vous avez un tableau comme celui-ci:

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

utiliser foreachpour résoudre ce problème:

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

cela vous donnera le résultat suivant:

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

et si vous voulez réorganiser l'ordre des clés,

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

Cette opération vous donnera des valeurs clés organisées comme ceci:

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

J'espère que cela effacera tout.


2

si vous avez un tableau comme celui-ci:

(utilisateurs est le nom du tableau)

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

et vous souhaitez supprimer les doublons ... puis:

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

peut être une solution: P


1

Une solution facile à lire, probablement pas la plus efficace:

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

Comme les gens disent que array_unique()c'est très lent, voici un extrait que j'utilise pour un tableau multidimensionnel à un niveau.

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

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

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

Référence du premier utilisateur à la note de la page de array_unique() fonction dans php.net


Anuj, pourriez-vous s'il vous plaît modifier votre réponse? Il y a un bug. Il devrait se terminer $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasher merci pour votre contribution. J'ai fait les changements et maintenant ça marche. :)
Anuj

1

Beaucoup de personnes m'ont demandé comment créer un tableau multidimensionnel unique. J'ai pris référence à votre commentaire et cela m'aide.

Tout d'abord, merci à @jeromegamez @daveilers pour votre solution. Mais chaque fois que je donnais la réponse, ils me demandaient comment fonctionnaient ces «sérialiser» et «désérialiser». C'est pourquoi je veux partager la raison de cela avec vous afin que cela aide plus de gens à comprendre le concept derrière cela.

J'explique pourquoi nous utilisons «sérialiser» et «désérialiser» par étapes:

Étape 1: convertir le tableau multidimensionnel en tableau unidimensionnel

Pour convertir le tableau multidimensionnel en tableau unidimensionnel, commencez par générer une représentation en flux d'octets de tous les éléments (y compris les tableaux imbriqués) à l'intérieur du tableau. La fonction serialize () peut générer une représentation en flux d'octets d'une valeur. Pour générer une représentation en flux d'octets de tous les éléments, appelez la fonction serialize () à l'intérieur de la fonction array_map () en tant que fonction de rappel. Le résultat sera un tableau unidimensionnel quel que soit le nombre de niveaux du tableau multidimensionnel.

Étape 2: rendre les valeurs uniques

Pour rendre ce tableau unidimensionnel unique, utilisez la fonction array_unique ().

Étape 3: le rétablir dans le tableau multidimensionnel

Bien que le tableau soit désormais unique, les valeurs ressemblent à une représentation de flux d'octets. Pour le rétablir dans le tableau multidimensionnel, utilisez la fonction unserialize ().

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

Merci encore pour tout ça.


0

Une alternative à la sérialisation et unique

$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 vous avez un tableau comme celui-ci

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

et vous voulez obtenir des tableaux comme celui-ci:

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

ou

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

un code suivant peut aider

    $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

J'ai beaucoup réfléchi à ce problème et j'ai déterminé que la solution optimale devait suivre deux règles.

  1. Pour l'évolutivité, modifiez le tableau en place; pas de copie vers un nouveau tableau
  2. Pour les performances, chaque comparaison ne doit être effectuée qu'une seule fois

Dans cet esprit et compte tenu de toutes les bizarreries de PHP, voici la solution que j'ai trouvée. Contrairement à certaines des autres réponses, il a la possibilité de supprimer des éléments en fonction de la ou des clés que vous souhaitez. Le tableau d'entrée devrait être des touches numériques.

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

Le seul inconvénient est que les clés ne sont pas en ordre à la fin de l'itération. Ce n'est pas un problème si vous n'utilisez ensuite que des boucles foreach, mais si vous devez utiliser une boucle for, vous pouvez mettre $input = array_values($input);après ce qui précède pour renuméroter les clés.


0

Sur la base de la réponse marquée comme correcte, en ajoutant ma réponse. Petit code ajouté juste pour réinitialiser les indices-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.