So entfernen Sie doppelte Werte aus einem mehrdimensionalen Array in PHP


306

Wie kann ich doppelte Werte aus einem mehrdimensionalen Array in PHP entfernen?

Beispielarray:

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
    )

)

Antworten:


637

Hier ist ein anderer Weg. Es werden keine Zwischenvariablen gespeichert.

Wir haben dies verwendet, um die Ergebnisse einer Vielzahl überlappender Abfragen zu de-duplizieren.

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

23
Aufgrund unserer Unserialisierung ist dies immer langsamer, je größer und komplexer das Array ist. Es gibt einen Grund, warum ich array_intersect_key verwendet habe (ein halbes Jahr vor dieser Antwort).
OIS

11
@OIS gut gerade getestet, hatte einen Tippfehler, aber es funktioniert .. danke Alter!: $ No_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array));
Trevorkavanaugh

3
Wenn der Index fortlaufend sein soll, verwenden Sie array_values, dh $ input = array_values ​​(array_map ("unserialize", array_unique (array_map ("serialize", $ input)));
lbsweek

4
Heutzutage würden Sie sich wahrscheinlich für json_encode und json_decode anstelle der PHP-Serialisierung entscheiden. sollte Vorteile für die angegebenen Werte haben und Sie werden nicht auf PHP-Serialisierungsdetails stoßen, die Schiffe mit serialisieren / unserialisieren und höchstwahrscheinlich unerwünscht sind.
hakre

2
Vorsicht, das serialize(array('a' => '1', 'b' => '1'))ist anders als serialize(array('b' => '1', 'a' => '1')). Diese Option schlägt für Arrays fehl, die als setsoder verwendet werden (hash)maps.
Andras Gyomrey

240

Seit 5.2.9 können Sie verwenden, array_unique()wenn Sie das SORT_REGULARFlag wie folgt verwenden :

array_unique($array, SORT_REGULAR);

Dadurch vergleicht die Funktion Elemente auf Gleichheit, als ob $a == $b sie verwendet würden, was für Ihren Fall perfekt ist.

Ausgabe

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

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

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

)

Beachten Sie jedoch, dass in der Dokumentation Folgendes angegeben ist:

array_unique() ist nicht für mehrdimensionale Arrays vorgesehen.


2
Ich denke, dies ist eine schnellere und klarere Lösung als die akzeptierte! lasst uns für diesen stimmen! :) Hmmm auf PHP-Seite können wir sehen, dass es nicht so schnell ist, wie ich dachte ...
Andron

4
Seltsamerweise funktioniert die Verwendung des SORT_REGULAR-Flags bei mir einfach nicht, um doppelte Arrays zu entfernen.
Stefan

4
@Stefan Du hast recht; es scheint nicht die richtigen Ergebnisse zu liefern, aber es ist wahrscheinlich ein Fehler, weil es mit PHP 7 funktioniert = /
Ja͢ck

4
Dies scheint auch in meinem Fall zu funktionieren, aber stört sich sonst noch jemand an dieser Notiz im Array_unique () -Dokument? php.net/manual/en/…
Arleigh Hix

2
@ Jack Sie haben Recht, dies ist ein Fehler ab PHP 5.6.23: eval.in/645675, aber behoben ab PHP 7.0.8: eval.in/645676
Zack Morris

63

Ich hatte ein ähnliches Problem, fand aber eine 100% funktionierende Lösung dafür.

<?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
Dies beantwortet eine andere Frage. Siehe hier: stackoverflow.com/questions/4585208/…
OIS

Tolle Funktion! und falls Sie es mit Objekten zu tun haben: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox

35

Ein anderer Weg. Erhält auch Schlüssel.

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

Bei großen Arrays ist diese Methode häufig mindestens 50% schneller als die akzeptierte Antwort.
Lorien Brune

21

Die Benutzerkommentare zur Dokumentation array_unique () haben viele Lösungen dafür. Hier ist einer von ihnen:

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

Noch eine Array_Unique für mehrfach demensionierte Arrays. Ich habe dies nur an zwei demensionierten Arrays getestet, aber es könnte wahrscheinlich für mehr verallgemeinert oder zur Verwendung von Rekursion gemacht werden.

Diese Funktion verwendet die Funktionen serialize, array_unique und unserialize, um die Arbeit zu erledigen.


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

Dies ist von http://ca3.php.net/manual/en/function.array-unique.php#57202 .


18

Wenn "Duplikate entfernen" bedeutet "Duplikate entfernen, aber eines dort lassen", besteht eine Lösung möglicherweise darin, zuerst array_unique(...)die "Bezeichnerspalte" anzuwenden und dann im ursprünglichen Array alle Schlüssel zu entfernen, die aus dem Spaltenarray entfernt wurden ::

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

Das Ergebnis ist:

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

Dadurch werden die doppelten Namen aus dem Array entfernt. einzigartig nach Schlüssel


Stellen Sie sicher, dass $arraydie Tasten bei "0" beginnen. Es ist möglich $array, dass die Schlüssel bei einer anderen Nummer beginnen, wenn dies $arraydas Ergebnis einer vorherigen Array-Manipulation ist. Verwenden Sie array_valuesdiese
Option


4

Verwenden Sie einfach die Option SORT_REGULAR als zweiten Parameter.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR funktioniert nur in PHP 7, da PHP 5 einen Fehler aufweist (obwohl @ r3wt gemäß der Dokumentation korrekt ist), siehe meinen Kommentar in der Antwort für ein ausführbares Beispiel stackoverflow.com/questions/307674/…
Zack Morris

Warum würdest du das hinzufügen? Es ist das gleiche wie diese Antwort, die über ein Jahr älter ist als Ihre: stackoverflow.com/a/18373723/870729
random_user_name

3

Wenn Sie Duplikate auf bestimmten Schlüsseln entfernen müssen, z. B. eine MySQL-ID, finden Sie hier eine einfache Funktion

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

Bonuspunkte Sie können eine Reihe von Schlüsseln übergeben und einen äußeren foreach hinzufügen, der jedoch pro zusätzlichem Schlüssel 2x langsamer ist.


3

Ein sehr einfacher und logischer Weg, um ein mehrdimensionales Array eindeutig zu machen, ist wie folgt:

Wenn Sie ein Array wie dieses haben:

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

Verwenden Sie foreach, um dies zu lösen:

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

Sie erhalten folgendes Ergebnis:

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

und wenn Sie die Reihenfolge der Schlüssel ändern möchten,

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

Mit dieser Operation erhalten Sie folgende Schlüsselwerte:

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

Ich hoffe das wird alles klären.


2

Wenn Sie ein Array wie dieses haben:

(Benutzer ist der Name des Arrays)

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

und Sie möchten Duplikate löschen ... dann:

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

kann eine Lösung sein: P.


1

Eine einfach zu lesende Lösung, wahrscheinlich nicht die effizienteste:

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

Wie die Leute sagen, array_unique()ist es sehr langsam, hier ist ein Ausschnitt, den ich für ein mehrdimensionales Array mit einer Ebene verwende.

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

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

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

Referenz erster Benutzer hat Hinweis zur array_unique() Funktionsseite in php.net beigetragen


Anuj, könntest du bitte deine Antwort bearbeiten? Es gibt einen Fehler. Es sollte enden $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasher danke für deine Eingabe. Ich habe die Änderungen vorgenommen und jetzt funktioniert es. :)
Anuj

1

Viele Leute haben mich gefragt, wie man ein einzigartiges mehrdimensionales Array erstellt. Ich habe auf Ihren Kommentar Bezug genommen und er hilft mir.

Zunächst einmal danke ich @jeromegamez @daveilers für Ihre Lösung. Aber jedes Mal, wenn ich die Antwort gab, fragten sie mich, wie diese "Serialisierung" und "Unserialisierung" funktioniert. Deshalb möchte ich den Grund dafür mit Ihnen teilen, damit mehr Menschen das Konzept dahinter verstehen.

Ich erkläre, warum wir in Schritten 'serialize' und 'unserialize' verwenden:

Schritt 1: Konvertieren Sie das mehrdimensionale Array in ein eindimensionales Array

Um das mehrdimensionale Array in ein eindimensionales Array zu konvertieren, generieren Sie zunächst eine Byte-Stream-Darstellung aller Elemente (einschließlich verschachtelter Arrays) innerhalb des Arrays. Die Funktion serialize () kann eine Byte-Stream-Darstellung eines Werts erzeugen. Um eine Byte-Stream-Darstellung aller Elemente zu generieren, rufen Sie die Funktion serialize () in der Funktion array_map () als Rückruffunktion auf. Das Ergebnis ist ein eindimensionales Array, unabhängig davon, wie viele Ebenen das mehrdimensionale Array hat.

Schritt 2: Machen Sie die Werte eindeutig

Verwenden Sie die Funktion array_unique (), um dieses eindimensionale Array eindeutig zu machen.

Schritt 3: Setzen Sie es auf das mehrdimensionale Array zurück

Obwohl das Array jetzt eindeutig ist, sehen die Werte wie eine Byte-Stream-Darstellung aus. Verwenden Sie die Funktion unserialize (), um es auf das mehrdimensionale Array zurückzusetzen.

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

Nochmals vielen Dank für all das.


0

Eine Alternative zu serialisieren und einzigartig

$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

Wenn Sie ein solches Array haben

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

und Sie möchten Arrays wie folgt erhalten:

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

oder

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

Ein folgender Code kann helfen

    $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

Ich habe viel über dieses Problem nachgedacht und festgestellt, dass die optimale Lösung zwei Regeln folgen sollte.

  1. Ändern Sie aus Gründen der Skalierbarkeit das vorhandene Array. Kein Kopieren in ein neues Array
  2. Für die Leistung sollte jeder Vergleich nur einmal durchgeführt werden

In diesem Sinne und angesichts aller Macken von PHP ist unten die Lösung aufgeführt, die ich gefunden habe. Im Gegensatz zu einigen anderen Antworten können Elemente basierend auf den gewünschten Schlüsseln entfernt werden. Es wird erwartet, dass das Eingabearray Zifferntasten sind.

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

Der einzige Nachteil ist, dass die Schlüssel nach Abschluss der Iteration nicht in Ordnung sind. Dies ist kein Problem, wenn Sie anschließend nur foreach-Schleifen verwenden. Wenn Sie jedoch eine for-Schleife verwenden müssen, können Sie $input = array_values($input);die Schlüssel nach dem oben Gesagten neu nummerieren.


0

Basierend auf der als richtig markierten Antwort, füge meine Antwort hinzu. Kleiner Code hinzugefügt, nur um die Indizes zurückzusetzen.

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.