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
    )

)
Ian
quelle

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)));
Daviler
quelle
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.

Jack
quelle
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'));

?>
Rajendrasinh
quelle
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);
}
OIS
quelle
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 .

Jeremy Ruten
quelle
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
        )

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

Mahak Choudhary
quelle
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
5

Einfache Lösung:

array_unique($array, SORT_REGULAR)
Saravanan DS
quelle
4

Verwenden Sie einfach die Option SORT_REGULAR als zweiten Parameter.

$uniqueArray = array_unique($array, SORT_REGULAR);
anghazi ghermezi
quelle
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.

r3wt
quelle
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.

Anand Agrawal
quelle
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.

Limon
quelle
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;

} 
Pixeline
quelle
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
quelle
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.

Manish
quelle
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"
        }
}

* /

Denis Laliberté
quelle
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;
milic
quelle
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.

Schlange
quelle
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))));
Gagan
quelle