Cara menghapus nilai duplikat dari array multi-dimensi di PHP

306

Bagaimana saya bisa menghapus nilai duplikat dari array multi-dimensi di PHP?

Contoh array:

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
sumber

Jawaban:

637

Ini cara lain. Tidak ada variabel perantara yang disimpan.

Kami menggunakan ini untuk menghapus duplikat hasil dari berbagai kueri yang tumpang tindih.

$input = array_map("unserialize", array_unique(array_map("serialize", $input)));
daveiler
sumber
23
Karena unserialize ini lebih lambat dan lebih lambat array lebih besar dan lebih kompleks. Ada alasan saya menggunakan array_intersect_key (setengah tahun sebelum jawaban ini).
OIS
11
@OIS juga baru saja mengujinya, memiliki kesalahan ketik tetapi berfungsi .. terima kasih Bung !: $ no_duplicates = array_intersect_key ($ array, array_unique (array_map ('serialize', $ array)));
trevorkavanaugh
3
jika Anda menginginkan indeks terus menerus, gunakan array_values ​​yaitu $ input = array_values ​​(array_map ("unserialize", array_unique (array_map ("serialize", $ input))));
lbsweek
4
Saat ini Anda mungkin akan memilih json_encode dan json_decode daripada serialisasi PHP. harus memiliki manfaat untuk nilai-nilai yang diberikan dan Anda tidak mengalami detail serialisasi PHP yang membuat cerita bersambung / tidak menggunakan kapal dan kemungkinan besar tidak diinginkan.
hakre
2
Waspadalah yang serialize(array('a' => '1', 'b' => '1'))berbeda dari serialize(array('b' => '1', 'a' => '1')). Opsi ini akan gagal untuk array yang digunakan sebagai setsatau (hash)maps.
Andras Gyomrey
240

Sejak 5.2.9 Anda dapat menggunakan array_unique()jika Anda menggunakan SORT_REGULARflag seperti:

array_unique($array, SORT_REGULAR);

Ini membuat fungsi membandingkan elemen untuk kesetaraan seolah $a == $bsedang digunakan, yang sempurna untuk kasus Anda.

Keluaran

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

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

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

)

Perlu diingat, bahwa dokumentasi menyatakan:

array_unique() tidak dimaksudkan untuk bekerja pada array multi dimensi.

Mendongkrak
sumber
2
Saya kira ini adalah solusi yang lebih cepat dan lebih jelas, daripada yang diterima! mari kita pilih yang ini! :) Hmmm di situs php kita dapat melihat bahwa itu tidak begitu cepat, seperti yang saya kira ...
Andron
4
Aneh bahwa menggunakan flag SORT_REGULAR tidak berfungsi untuk saya, untuk menghapus array duplikat.
Stefan
4
@Stefan Anda benar; sepertinya tidak memberikan hasil yang benar, tapi itu mungkin bug karena bekerja dengan PHP 7 = /
Ja͢ck
4
Ini juga tampaknya berfungsi dalam kasus saya, tetapi adakah orang lain yang terganggu dengan catatan ini di array_unique () doc? php.net/manual/en/…
Arleigh Hix
2
@Jack Anda benar ini adalah bug pada PHP 5.6.23: eval.in/645675 tetapi sudah diperbaiki pada PHP 7.0.8: eval.in/645676
Zack Morris
63

Saya memiliki masalah yang sama tetapi saya menemukan solusi 100% berfungsi untuk itu.

<?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
sumber
1
Ini menjawab pertanyaan yang berbeda. Lihat di sini: stackoverflow.com/questions/4585208/…
OIS
Fungsi hebat! dan jika Anda berurusan dengan objek: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox
35

Cara lain. Akan menyimpan kunci juga.

function array_unique_multidimensional($input)
{
    $serialized = array_map('serialize', $input);
    $unique = array_unique($serialized);
    return array_intersect_key($input, $unique);
}
OIS
sumber
Untuk array besar, metode ini seringkali paling tidak 50% lebih cepat dari jawaban yang diterima.
Lorien Brune
21

Komentar pengguna pada dokumentasi array_unique () memiliki banyak solusi untuk ini. Ini salah satunya:

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

Array_Unique lain untuk array multi-demensi. Saya hanya menguji ini pada array dua-dimensi, tetapi mungkin bisa digeneralisasi untuk lebih, atau dibuat untuk menggunakan rekursi.

Fungsi ini menggunakan fungsi serialize, array_unique, dan unserialize untuk melakukan pekerjaan.


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

Ini dari http://ca3.php.net/manual/en/function.array-unique.php#57202 .

Jeremy Ruten
sumber
18

Jika "hapus duplikat" berarti "hapus duplikat, tetapi biarkan duplikat di sana", sebuah solusi mungkin untuk menerapkan array_unique(...)pada "kolom pengidentifikasi" pertama dan kemudian untuk menghapus dalam array asli semua kunci, yang telah dihapus dari array kolom :

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

Hasilnya adalah:

Array
(
    [0] => Array
        (
            [id] => 123
            [foo] => aaa
            [bar] => bbb
        )

    [2] => Array
        (
            [id] => 567
            [foo] => eee
            [bar] => fff
        )

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

Ini akan menghapus nama duplikat dari array. unik dengan kunci

Mahak Choudhary
sumber
Pastikan bahwa $arraykunci mulai dari "0". Mungkin saja $arraykunci mulai dari nomor lain jika $arraymerupakan hasil dari manipulasi array sebelumnya. Gunakan array_valuesuntuk mengatur ulang tombol kembali ke "0"
stevevance
5

Solusi sederhana:

array_unique($array, SORT_REGULAR)
Saravanan DS
sumber
4

Cukup gunakan opsi SORT_REGULAR sebagai parameter kedua.

$uniqueArray = array_unique($array, SORT_REGULAR);
anghazi ghermezi
sumber
1
SORT_REGULAR hanya berfungsi di PHP 7 karena PHP 5 memiliki bug (walaupun @ r3wt sudah benar sesuai dengan dokumentasi), lihat komentar saya di jawaban untuk contoh runnable stackoverflow.com/questions/307674/…
Zack Morris
Mengapa Anda menambahkan ini? Ini sama dengan jawaban ini, yang lebih dari setahun lebih tua dari milik Anda: stackoverflow.com/a/18373723/870729
random_user_name
3

jika Anda perlu menghilangkan duplikat pada kunci tertentu, seperti id mysqli, inilah fungsi sederhana

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

Poin Bonus Anda bisa melewati array kunci dan menambahkan foreach luar, tetapi itu akan lebih lambat 2x per kunci tambahan.

r3wt
sumber
3

Cara yang sangat mudah dan logis untuk Unik array multi dimensi adalah sebagai berikut,

Jika Anda memiliki array seperti ini:

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

gunakan foreachuntuk memecahkan ini:

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

itu akan memberi Anda hasil sebagai berikut:

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

dan jika Anda ingin mengatur ulang urutan tombol,

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

Operasi ini akan memberi Anda nilai-nilai kunci yang diatur seperti ini:

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

Saya harap ini akan menghapus semuanya.

Anand agrawal
sumber
2

jika Anda memiliki array seperti ini:

(pengguna adalah nama array)

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

dan Anda ingin menghapus duplikat ... lalu:

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

bisa menjadi solusinya: P

Limon
sumber
1

Solusi yang mudah dibaca, mungkin bukan yang paling efisien:

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
sumber
1

Seperti yang orang katakan array_unique()sangat lambat, di sini adalah potongan yang saya gunakan untuk array multidimensi satu tingkat.

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

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

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

Referensi pertama yang dikontribusikan pengguna mencatat array_unique() halaman fungsi di php.net

Anuj
sumber
Anuj, bisakah Anda mengedit jawaban Anda? Ada bug. Seharusnya diakhiri $output = array_map('unserialize', array_keys($result));
keyboardSmasher
@keyboardSmasher terima kasih atas masukan Anda. Saya membuat perubahan dan sekarang berhasil. :)
Anuj
1

Banyak orang bertanya kepada saya bagaimana membuat array multidimensi Unik. Saya telah mengambil referensi dari komentar Anda dan itu membantu saya.

Pertama-tama, Terima kasih kepada @jeromegamez @daveiler untuk solusi Anda. Tetapi setiap kali saya memberikan jawaban, mereka bertanya kepada saya bagaimana 'serialisasi' dan 'unserialize' ini bekerja. Itu sebabnya saya ingin berbagi alasan ini dengan Anda sehingga akan membantu lebih banyak orang untuk memahami konsep di balik ini.

Saya menjelaskan mengapa kami menggunakan 'serialize' dan 'unserialize' dalam langkah-langkah:

Langkah 1: Konversi array multidimensi menjadi array satu dimensi

Untuk mengonversi array multidimensi menjadi array satu dimensi, pertama-tama buat representasi aliran byte dari semua elemen (termasuk array bersarang) di dalam array. fungsi serialize () dapat menghasilkan representasi stream byte dari suatu nilai. Untuk menghasilkan representasi aliran byte dari semua elemen, panggil fungsi serialize () di dalam fungsi array_map () sebagai fungsi callback. Hasilnya akan menjadi array satu dimensi tidak peduli berapa banyak level yang dimiliki array multidimensi.

Langkah 2: Buat nilainya unik

Untuk membuat array satu dimensi ini unik, gunakan fungsi array_unique ().

Langkah 3: Kembalikan ke array multidimensi

Meskipun array sekarang unik, nilainya terlihat seperti representasi stream byte. Untuk mengembalikannya ke array multidimensi, gunakan fungsi unserialize ().

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

Terima kasih sekali lagi untuk semua ini.

Manish
sumber
0

Alternatif untuk bersambung dan unik

$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é
sumber
0

Jika Anda memiliki array seperti ini

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

dan Anda ingin mendapatkan array seperti ini:

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

atau

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

kode berikut dapat membantu

    $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
sumber
0

Saya telah memberikan masalah ini banyak pemikiran dan telah memutuskan bahwa solusi optimal harus mengikuti dua aturan.

  1. Untuk skalabilitas, modifikasi array di tempat; tidak menyalin ke array baru
  2. Untuk kinerja, setiap perbandingan harus dilakukan hanya sekali

Dengan pemikiran itu dan mengingat semua keanehan PHP, di bawah ini adalah solusi yang saya buat. Tidak seperti beberapa jawaban lain, ia memiliki kemampuan untuk menghapus elemen berdasarkan kunci apa pun yang Anda inginkan. Array input diharapkan menjadi tombol angka.

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

Satu-satunya kelemahan adalah bahwa kunci tidak berurutan ketika iterasi selesai. Ini bukan masalah jika Anda selanjutnya hanya menggunakan foreach loop, tetapi jika Anda perlu menggunakan for loop, Anda dapat menempatkan $input = array_values($input);setelah di atas untuk memberi nomor baru tombol.

Ular
sumber
0

Berdasarkan pada Jawaban yang ditandai sebagai benar, tambahkan jawaban saya. Kode kecil ditambahkan hanya untuk mengatur ulang indeks-

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
Gagan
sumber