PHP'de çok boyutlu bir diziden yinelenen değerler nasıl kaldırılır


306

PHP'de çok boyutlu bir diziden yinelenen değerleri nasıl kaldırabilirim?

Örnek dizi:

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
    )

)

Yanıtlar:


637

İşte başka bir yol. Hiçbir ara değişken kaydedilmez.

Bunu, örtüşen çeşitli sorguların sonuçlarını çoğaltmak için kullandık.

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

23
Serileştirme nedeniyle, bu dizi daha yavaş ve yavaştır. Array_intersect_key (bu yanıttan yarım yıl önce) kullanmamın bir nedeni var.
OIS

11
@OIS iyi test, bir yazım hatası vardı ama işe yarıyor .. teşekkürler dostum !: $ no_duplicates = array_intersect_key ($ dizi, dizi_unique (dizi_map ('seri hale', $ dizi)));
trevorkavanaugh

3
dizinin sürekli olmasını istiyorsanız, dizi_değeri kullanın yani $ input = dizi_değeri (array_map ("unserialize", dizi_unique (dizi_map ("serialize", $ input))));
lbsweek

4
Bugünlerde muhtemelen PHP serileştirmesi yerine json_encode ve json_decode'u tercih edersiniz. sağlanan değerler için faydaları olmalıdır ve gemileri serileştiren / serileştirmeyen ve büyük olasılıkla istenmeyen PHP serileştirme ayrıntılarıyla karşılaşmazsınız.
hakre

2
serialize(array('a' => '1', 'b' => '1'))Fark etmeyin serialize(array('b' => '1', 'a' => '1')). Bu seçenek setsveya olarak kullanılan diziler için başarısız olur (hash)maps.
Andras Gyomrey

240

5.2.9'dan beri bayrağı array_unique()şu şekilde kullanıyorsanız kullanabilirsiniz SORT_REGULAR:

array_unique($array, SORT_REGULAR);

Bu, fonksiyonun $a == $b, kullanılan gibi eşitlik unsurlarını karşılaştırmasını sağlar , bu da sizin durumunuz için mükemmeldir.

Çıktı

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

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

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

)

Bununla birlikte, belgelerin şunları belirttiğini unutmayın:

array_unique() çok boyutlu diziler üzerinde çalışmak için tasarlanmamıştır.


2
Sanırım bu, kabul edilenden daha hızlı ve daha açık bir çözüm! bunun için oy verelim! :) Php sitesinde Hmmm düşündüğüm kadar hızlı olmadığını görebiliriz ...
Andron

4
Yinelenen dizileri kaldırmak için SORT_REGULAR bayrağını kullanmanın benim için işe yaramadığı garip.
Stefan

4
@Stefan Haklısın; doğru sonuçları vermiyor gibi görünüyor, ancak PHP 7 ile çalıştığı için büyük olasılıkla bir hata = =
Ja͢ck

4
Bu da benim durumumda çalışıyor gibi görünüyor ama array_unique () doc bu nottan başka kimse rahatsız mı? php.net/manual/tr/…
Arleigh Hix

2
@Jack Haklısınız, bu PHP 5.6.23: eval.in/645675 itibariyle bir hata ama PHP 7.0.8 itibariyle düzeltildi: eval.in/645676
Zack Morris

63

Benzer bir sorunum vardı ama bunun için% 100 çalışma çözümü buldum.

<?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
Bu farklı bir soruyu cevaplıyor. Buraya bakın: stackoverflow.com/questions/4585208/…
OIS

Harika fonksiyon! ve nesnelerle ilgileniyorsanız: if (! isset ($ array -> $ v -> $ key)) $ array [$ v -> $ key] = & $ v;
Playnox

35

Diğer yol. Anahtarları da koruyacaktır.

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

Büyük diziler için, bu yöntem genellikle kabul edilen yanıttan en az% 50 daha hızlıdır.
Lorien Brune

21

Array_unique () belgelerindeki kullanıcı yorumları bunun birçok çözümüne sahiptir. İşte bunlardan biri:

kenrbnsn at rbnsn dot com
27 Eylül 2005 12:09

Çok demonte diziler için bir başka Array_Unique. Bunu sadece iki demetli dizilerde test ettim, ancak muhtemelen daha fazlası için genelleştirilebilir veya özyineleme kullanmak için yapılabilir.

Bu işlev işi yapmak için serialize, array_unique ve unserialize işlevlerini kullanır.


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

Bu http://ca3.php.net/manual/en/function.array-unique.php#57202 adresinden .


18

"Yinelenenleri kaldır", "yinelenenleri kaldır, ancak bir tanesine izin ver" anlamına gelirse array_unique(...), önce "tanımlayıcı sütunu" nu uygulamak ve ardından orijinal dizide sütun dizisinden kaldırılan tüm anahtarları kaldırmak için bir çözüm olabilir :

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

Sonuç:

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

Bu, yinelenen adları diziden kaldırır. anahtar ile benzersiz


$arrayTuşlarının "0" ile başladığından emin olun . Önceki dizi işleminin bir sonucuysa, olası $arraytuşları başka bir sayıdan başlar $array. Kullanım array_valuesgeri "0" anahtarlarını sıfırlamak için
stevevance


4

İkinci parametre olarak SORT_REGULAR seçeneğini kullanın.

$uniqueArray = array_unique($array, SORT_REGULAR);

1
SORT_REGULAR sadece PHP 7'de çalışır çünkü PHP 5'in bir hatası vardır (@ r3wt belgelere göre doğru olsa da), çalıştırılabilir bir örnek için cevabımdaki yorumuma bakın stackoverflow.com/questions/307674/…
Zack Morris

Bunu neden eklesin?
Sizden

3

mysqli kimliği gibi belirli tuşlardaki kopyaları kaldırmanız gerekiyorsa, işte basit bir funciton

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

Bonus Puanları Bir dizi anahtar iletebilir ve bir dış foreach ekleyebilirsiniz, ancak ek anahtar başına 2 kat daha yavaş olacaktır.


3

Çok boyutlu bir diziyi Benzersizleştirmenin çok kolay ve mantıklı bir yolu aşağıdaki gibidir,

Böyle bir diziniz varsa:

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

foreachBunu çözmek için kullanın :

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

size aşağıdaki sonucu verecektir:

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

ve tuşların sırasını yeniden düzenlemek istiyorsanız,

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

Bu işlem size aşağıdaki gibi düzenlenmiş anahtar değerleri verecektir:

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

Umarım bu her şeyi temizler.


2

böyle bir diziniz varsa:

(kullanıcılar dizinin adıdır)

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

ve kopyaları silmek istiyorsanız ... o zaman:

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

bir çözüm olabilir: P


1

Kolay okunan bir çözüm, muhtemelen en verimli değil:

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

İnsanların söylediği gibi array_unique()çok yavaş, işte bir seviyeli çok boyutlu dizi için kullandığım bir parçacık.

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

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

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

Referans ilk kullanıcı php.net işlev sayfası not katkıdaarray_unique()


Anuj, lütfen cevabını düzenleyebilir misin? Bir hata var. Sona ermeli $output = array_map('unserialize', array_keys($result));
klavye

@keyboardSmasher girişiniz için teşekkür ederiz. Değişiklikleri yaptım ve şimdi çalışıyor. :)
Anuj

1

Birçok kişi Benzersiz çok boyutlu diziyi nasıl yapacağımı sordu. Yorumunuzdan referans aldım ve bu bana yardımcı oluyor.

Her şeyden önce, çözümünüz için @ jeromegamez @ daveilers sayesinde. Ama her cevap verdiğimde bana bunun 'serileştirme' ve 'dizileştirme' işlemlerinin nasıl çalıştığını sordular. Bu yüzden bunun nedenini sizinle paylaşmak istiyorum, böylece daha fazla insanın bunun arkasındaki kavramı anlamasına yardımcı olacak.

Adımlarla neden 'serileştir' ve 'serileştirme' kullandığımızı açıklıyorum:

Adım 1: Çok boyutlu diziyi tek boyutlu diziye dönüştürün

Çok boyutlu diziyi tek boyutlu bir diziye dönüştürmek için, önce dizi içindeki tüm öğelerin (iç içe diziler dahil) bayt akışı gösterimini oluşturun. serialize () işlevi bir değerin bayt akışı gösterimini oluşturabilir. Tüm öğelerin bayt akışı temsilini oluşturmak için, array_map () işlevi içindeki serialize () işlevini geri arama işlevi olarak çağırın. Sonuç, çok boyutlu dizinin kaç düzeyi olursa olsun tek boyutlu bir dizi olacaktır.

2. Adım: Değerleri benzersiz yapın

Bu tek boyutlu diziyi benzersiz yapmak için array_unique () işlevini kullanın.

Adım 3: Çok boyutlu diziye geri döndürün

Dizi artık benzersiz olsa da, değerler bayt akışı temsiline benziyor. Çok boyutlu diziye geri döndürmek için unserialize () işlevini kullanın.

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

Tüm bunlar için tekrar teşekkürler.


0

Serileştirmeye ve benzersiz bir alternatif

$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

Böyle bir diziniz varsa

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

ve böyle diziler almak istiyorsunuz:

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

veya

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

aşağıdaki kod yardımcı olabilir

    $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

Bu sorunu çok düşündüm ve en uygun çözümün iki kurala uyması gerektiğini belirledim.

  1. Ölçeklenebilirlik için diziyi yerinde değiştirin; yeni bir diziye kopyalama yok
  2. Performans için her karşılaştırma yalnızca bir kez yapılmalıdır.

Bunu akılda tutarak ve PHP'nin tüm tuhaflıkları göz önüne alındığında, aşağıda geldiğim çözüm. Diğer bazı cevapların aksine, istediğiniz anahtar (lar) a dayalı öğeleri kaldırma özelliğine sahiptir. Giriş dizisinin sayısal tuşlar olması beklenir.

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

Tek dezavantajı, yineleme tamamlandığında tuşların düzgün olmamasıdır. Daha sonra yalnızca foreach döngülerini kullanıyorsanız bu bir sorun değildir, ancak for döngüsü kullanmanız gerekiyorsa $input = array_values($input);, anahtarları yeniden numaralandırmak için yukarıdakilerden sonra koyabilirsiniz .


0

Doğru olarak işaretlenen Cevaba dayanarak cevabımı ekledim. Sadece endeksleri sıfırlamak için küçük kod eklendi

$input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.