Jak usunąć zduplikowane wartości z wielowymiarowej tablicy w PHP


306

Jak mogę usunąć zduplikowane wartości z wielowymiarowej tablicy w PHP?

Przykładowa tablica:

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
    )

)

Odpowiedzi:


637

Oto inny sposób. Żadne zmienne pośrednie nie są zapisywane.

Wykorzystaliśmy to do zduplikowania wyników z wielu pokrywających się zapytań.

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

23
Z powodu unserializacji jest to wolniejsze i wolniejsze, im większa i bardziej złożona jest tablica. Jest powód, dla którego użyłem array_intersect_key (pół roku przed tą odpowiedzią).
OIS

11
@OIS właśnie to przetestowałem, miałem literówkę, ale działa .. dzięki stary !: $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array)));
trevorkavanaugh

3
jeśli chcesz, aby indeks był ciągły, użyj wartości_kolejki, tj. $ input = wartości_macierzy (map_macierzy („unserialize”, tablica_unikalna (map_macierzy („serializacja”, $ wejście)));
lbsweek

4
W dzisiejszych czasach prawdopodobnie zdecydowałbyś się na json_encode i json_decode zamiast serializacji PHP. powinny mieć zalety dla podanych wartości i nie natrafisz na szczegóły serializacji PHP, które serializują / odserializowują statki i najprawdopodobniej są niepożądane.
hakre

2
Uwaga, serialize(array('a' => '1', 'b' => '1'))różni się od serialize(array('b' => '1', 'a' => '1')). Ta opcja nie powiedzie się w przypadku tablic używanych jako setslub (hash)maps.
Andras Gyomrey,

240

Od wersji 5.2.9 możesz używać, array_unique()jeśli używasz SORT_REGULARflagi w taki sposób:

array_unique($array, SORT_REGULAR);

To sprawia, że ​​funkcja porównuje elementy pod kątem równości, jakby $a == $bbyły używane, co jest idealne dla twojego przypadku.

Wynik

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

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

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

)

Należy jednak pamiętać, że dokumentacja stanowi:

array_unique() nie jest przeznaczony do pracy na tablicach wielowymiarowych.


2
Wydaje mi się, że jest to szybsze i bardziej przejrzyste rozwiązanie niż przyjęte! głosujmy na to! :) Hmmm na stronie php widzimy, że nie jest tak szybko, jak myślałem ...
Andron

4
Dziwne, że użycie flagi SORT_REGULAR po prostu nie działa, aby usunąć zduplikowane tablice.
Stefan

4
@Stefan Masz rację; wydaje się, że nie daje poprawnych wyników, ale prawdopodobnie jest to błąd, ponieważ działa z PHP 7 = /
Ja͢ck

4
Wydaje się, że to również działa w moim przypadku, ale czy komuś innemu przeszkadza ta notatka w dokumencie array_unique ()? php.net/manual/en/…
Arleigh Hix

2
@ Jack Masz rację, jest to błąd w PHP 5.6.23: eval.in/645675, ale został naprawiony w PHP 7.0.8: eval.in/645676
Zack Morris

63

Miałem podobny problem, ale znalazłem dla niego 100% działające rozwiązanie.

<?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
To odpowiada na inne pytanie. Zobacz tutaj: stackoverflow.com/questions/4585208/…
OIS

Świetna funkcja! a jeśli masz do czynienia z obiektami: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox,

35

Inny sposób. Zachowa również klucze.

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

W przypadku dużych tablic ta metoda jest często co najmniej o 50% szybsza niż zaakceptowana odpowiedź.
Lorien Brune

21

Komentarze użytkowników do dokumentacji array_unique () mają na to wiele rozwiązań. Oto jeden z nich:

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

Jeszcze jeden Array_Unique dla tablic wielowymiarowych. Przetestowałem to tylko na tablicach z dwiema odmianami, ale prawdopodobnie można by je uogólnić na więcej lub użyć rekurencji.

Ta funkcja korzysta z funkcji serialize, array_unique i unserialize.


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

Pochodzi z http://ca3.php.net/manual/en/function.array-unique.php#57202 .


18

Jeśli „usuń duplikaty” oznacza „usuń duplikaty, ale pozwól na to”, rozwiązaniem może być array_unique(...)najpierw zastosowanie „kolumny identyfikatora”, a następnie usunięcie w oryginalnej tablicy wszystkich kluczy, które zostały usunięte z tablicy kolumn :

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

Wynik to:

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

Spowoduje to usunięcie zduplikowanych nazw z tablicy. unikatowy według klucza


Upewnij się, że $arrayklucze zaczynają się od „0”. Możliwe, $arrayże klucze zaczynają się na inny numer, jeśli $arrayjest wynikiem wcześniejszej manipulacji tablicą. Użyj, array_valuesaby zresetować klawisze z powrotem do „0”
stevevance


4

Wystarczy użyć opcji SORT_REGULAR jako drugiego parametru.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR działa tylko w PHP 7, ponieważ PHP 5 ma błąd (chociaż @ r3wt jest poprawny zgodnie z dokumentacją), zobacz mój komentarz w odpowiedzi na przykładowy przykład stackoverflow.com/questions/307674/…
Zack Morris

Dlaczego miałbyś to dodawać? Jest to ta sama odpowiedź, która jest ponad rok starsza od twojej: stackoverflow.com/a/18373723/870729
nazwa_użytkownika losowego

3

jeśli chcesz wyeliminować duplikaty określonych kluczy, takich jak identyfikator mysqli, oto prosta funkcja

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

Punkty bonusowe Możesz przekazać tablicę kluczy i dodać zewnętrzny foreach, ale będzie 2x wolniejszy na każdy dodatkowy klucz.


3

Bardzo łatwy i logiczny sposób na unikatową tablicę wielowymiarową jest następujący,

Jeśli masz taką tablicę:

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

użyj, foreachaby rozwiązać ten problem:

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

da ci następujący wynik:

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

a jeśli chcesz zmienić kolejność klawiszy,

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

Ta operacja da ci uporządkowane kluczowe wartości:

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

Mam nadzieję, że to wszystko wyczyści.


2

jeśli masz taką tablicę:

(users to nazwa tablicy)

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

i chcesz usunąć duplikaty ... to:

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

może być rozwiązaniem: P


1

Łatwe do odczytania rozwiązanie, prawdopodobnie nie najbardziej wydajne:

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

Jak mówią ludzie, array_unique()jest bardzo powolny, oto fragment, którego używam dla wielowymiarowej tablicy na jednym poziomie.

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

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

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

Odwołaj się do pierwszego komentarza od array_unique() strony funkcji w php.net


Anuj, czy mógłbyś edytować swoją odpowiedź? Wystąpił błąd. Powinno się skończyć $output = array_map('unserialize', array_keys($result));
keyboardSmasher

@keyboardSmasher dziękuję za wkład. Wprowadziłem zmiany i teraz działa. :)
Anuj

1

Wiele osób pytało mnie, jak zrobić tablicę wielowymiarową Unique. Wziąłem odniesienie z twojego komentarza i to mi pomaga.

Przede wszystkim dzięki @jeromegamez @daveilers za twoje rozwiązanie. Ale za każdym razem, gdy udzielałem odpowiedzi, pytali mnie, jak działa ta funkcja „serializacji” i „nieserializacji”. Dlatego chcę podzielić się z tobą tym powodem, aby pomóc większej liczbie osób zrozumieć koncepcję tego.

Wyjaśniam, dlaczego używamy „serializacji” i „odserializowania” etapami:

Krok 1: Przekształć tablicę wielowymiarową w tablicę jednowymiarową

Aby przekonwertować tablicę wielowymiarową na tablicę jednowymiarową, najpierw wygeneruj bajtową reprezentację strumienia wszystkich elementów (w tym tablic zagnieżdżonych) wewnątrz tablicy. Funkcja serialize () może generować bajtową reprezentację strumienia wartości. Aby wygenerować bajtową reprezentację strumienia wszystkich elementów, wywołaj funkcję serialize () wewnątrz funkcji array_map () jako funkcję zwrotną. Wynikiem będzie macierz jednowymiarowa, bez względu na liczbę poziomów macierzy wielowymiarowej.

Krok 2: Spraw, by wartości były unikalne

Aby ta tablica jednowymiarowa była unikalna, użyj funkcji array_unique ().

Krok 3: Przywróć go do tablicy wielowymiarowej

Chociaż tablica jest teraz unikalna, wartości wyglądają jak reprezentacja strumienia bajtów. Aby przywrócić go z powrotem do tablicy wielowymiarowej, użyj funkcji unserialize ().

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

Jeszcze raz dziękuję za to wszystko.


0

Alternatywa dla serializacji i wyjątkowa

$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

Jeśli masz taką tablicę

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

i chcesz uzyskać takie tablice:

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

lub

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

poniższy kod może pomóc

    $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

Zastanowiłem się nad tym problemem i zdecydowałem, że optymalne rozwiązanie powinno przestrzegać dwóch zasad.

  1. Aby uzyskać skalowalność, zmodyfikuj tablicę na miejscu; bez kopiowania do nowej tablicy
  2. W celu uzyskania wydajności każde porównanie należy wykonać tylko raz

Mając to na uwadze i biorąc pod uwagę wszystkie dziwactwa PHP, poniżej znajduje się rozwiązanie, które wymyśliłem. W przeciwieństwie do niektórych innych odpowiedzi ma możliwość usuwania elementów na podstawie dowolnych kluczy. Oczekuje się, że tablicą wejściową będą klawisze numeryczne.

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

Jedyną wadą jest to, że klucze nie są w porządku po zakończeniu iteracji. Nie stanowi to problemu, jeśli następnie używasz tylko pętli foreach, ale jeśli potrzebujesz użyć pętli for, możesz umieścić $input = array_values($input);po powyższym, aby zmienić numerację kluczy.


0

Na podstawie odpowiedzi oznaczonej jako poprawna, dodając moją odpowiedź. Dodano mały kod, aby zresetować indeksy

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.