PHP dizi değerine göre silme (anahtar değil)


886

Aşağıdaki gibi bir PHP dizisi var:

$messages = [312, 401, 1599, 3, ...];

Değeri içeren öğeyi silmek istiyorum $del_val(örneğin, $del_val=401), ama anahtarını bilmiyorum. Bu yardımcı olabilir: her değer yalnızca bir kez orada olabilir .

Bu görevi gerçekleştirmek için en basit işlevi arıyorum, lütfen.


1
@Adam Strudwick Ama bu dizide birçok silme işleminiz varsa, bunu bir kez yinelemek ve anahtarını değerle aynı yapmak daha iyi olur mu?
dzona


Yanıtlar:


1566

Kullanılması array_search()ve unsetaşağıdakileri deneyin:

if (($key = array_search($del_val, $messages)) !== false) {
    unset($messages[$key]);
}

array_search()bu öğeyi kullanarak orijinal diziden kaldırmak için kullanılabilen bulduğu öğenin anahtarını döndürür unset(). FALSEBaşarısızlığa dönecektir , ancak başarı üzerine yanlış-y değeri döndürebilir (anahtarınız 0örneğin olabilir ), bu yüzden katı karşılaştırma !==operatörü kullanılır.

if()İfadesi olmadığını kontrol edecek array_search()bir değer döndü ve yaptım keşke bir eylem gerçekleştirir.


14
$ Messages = array_diff ($ messages, array ($ del_val)) da çalışır mı? Performansta daha iyi olur mu?
Adam Strudwick

9
@Adam Neden test etmiyorsun? Benim duygu olduğunu array_diff()o oluyor daha yavaş olacağını iki karşılaştıran sadece içinden arama yapmak yerine diziler biri gibi array_search().
Bojangles

22
Bu geçerli olsa da, böyle ifadelere değer atamaktan kaçınmalısınız. Sadece seni belaya sokar.
adlawson

17
Ya $keyolduğunu 0?
evan

16
Aradığınız değerin bir anahtarı 0veya başka bir falsey değeri varsa, değerin ayarını kaldırmaz ve kodunuz çalışmaz. Test etmelisin $key === false. (değiştir- anladın)
evan

673

Bir öğeyi diziden silmek temelde sadece bir öğeyle ayarlanan farktır .

array_diff( [312, 401, 15, 401, 3], [401] ) // removing 401 returns [312, 15, 3]

Güzelce genelleştirir, isterseniz aynı anda istediğiniz kadar öğeyi kaldırabilirsiniz.

Feragatname: Benim çözümüm, dizinin yeni bir kopyasını oluştururken, eskisini değiştiren kabul edilen cevabın aksine sağlam tutar. İhtiyacınız olanı seçin.


32
Bu yalnızca bir dizeye dönüştürülebilen nesneler için kullanılabilir
nischayn22

7
Söylediğim için 'Ayrıştırma Hatası' alıyorum [$element], array($element)bunun yerine kullandım . Biggie yok, ama benzer bir sorunu olan herkesin yalnız olmadıklarını bilmek istediler
Angad

8
Tabii, PHP 5.4 şimdi eski gösterimi bırakmak için çoğunluk olduğunu varsaydım. Yorum için teşekkürler.
Rok Kralj

22
Bazı nedenlerden dolayı array_diff, beklediğiniz gibi (string) $elem1 === (string) $elem2değil, eşitlik durumu olarak kullanıldığını belirtmek gerekir $elem1 === $elem2. @ Nischayn22'nin işaret ettiği konu bunun bir sonucudur. Bir şeyin rasgele elemanlar (nesneler olabilir) dizileri için çalışacak bir yardımcı program işlevi olarak kullanılmasını istiyorsanız, Bojangle'ın yanıtı bu nedenle daha iyi olabilir.
Mark Amery

4
Ayrıca, bu yöntemin her bağımsız değişken için dahili olarak bir sıralama gerçekleştirdiğini array_diff()ve böylece çalışma zamanını O (n) 'den O (n lg n)' ye kadar ittiğini unutmayın.
Ja͢ck

115

İlginç bir yol array_keys():

foreach (array_keys($messages, 401, true) as $key) {
    unset($messages[$key]);
}

array_keys()Fonksiyonu (Karşılaştırma için yani === kullanarak) belirli bir değeri için ve sıkı kontrol gerekli olup olmadığını sadece anahtarlarını dönmek için iki ek parametre alır.

Bu, aynı değere sahip birden fazla dizi öğesini de kaldırabilir (örn. [1, 2, 3, 3, 4]).


3
@ blasteralfredΨ Doğrusal bir arama O (n) 'dir; Bunun neden bir sorun olduğunu düşündüğünden emin değilim.
Ja͢ck

1
Evet, bu birden fazla dizi öğesi / anahtarı seçmek için etkilidir.
Oki Erie Rinaldi

3
Bu, tüm benzersiz değerleri içermeyen diziler için en iyisidir.
Derokorian

Sorun şu ki, tuşların dizinini sıralı bırakıyor: [0] - a, [2] - b ([1] gitti ama dizi hala özlüyor)
Rodniko

3
@Rodniko bu durumda da ihtiyacınız olacak array_values(); geri kalan anahtarlar hala aynı sırada, bu yüzden teknik olarak "sıralanmamış" değil
Ja͢ck

55

Dizinizin bu değere sahip yalnızca bir öğe içereceğini kesin olarak biliyorsanız,

$key = array_search($del_val, $array);
if (false !== $key) {
    unset($array[$key]);
}

Bununla birlikte, değeriniz dizinizde birden fazla ortaya çıkabilirse, bunu yapabilirsiniz

$array = array_filter($array, function($e) use ($del_val) {
    return ($e !== $del_val);
});

Not: İkinci seçenek yalnızca Kapanışlarla PHP5.3 + için çalışır


41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);

11
Bu yalnızca diziniz kaldırmaya çalıştığınız değerlerden başka yinelenen değerler içermediğinde çalışır.
jberculo

2
@jberculo ve bazen tam olarak neye ihtiyacınız olduğunu, bazı durumlarda bana benzersiz bir dizi yapmaktan kurtarır aswel
DarkMukke

Belki, ama temelde başka bir şey için kullanılan ve amaçlanan bir fonksiyonun sadece şanslı bir yan etkisi olmak yerine, bunu yapmak için özel olarak tasarlanmış fonksiyonları kullanırdım. Ayrıca kodunuzu daha az şeffaf hale getirir.
jberculo

Mesajda "her değer yalnızca bir kez orada olabilir" ifadesi çalışmalıdır. Poster smae değişken isimlerini kullanıyor olsa ve biraz açıklama
ekleseydi

2
Görünüşe göre bu seçilen çözüm ile karşılaştırıldığında en hızlı, ben küçük kıyaslama yaptım.
AMB

28

Aşağıdaki koda bir göz atın:

$arr = array('nice_item', 'remove_me', 'another_liked_item', 'remove_me_also');

Yapabilirsin:

$arr = array_diff($arr, array('remove_me', 'remove_me_also'));

Ve bu size şu diziyi verecektir:

array('nice_item', 'another_liked_item')

1
İlişkilendirilebilir diziler için array_diff_assoc ()
theCodeMachine

5
Bunun bu cevaptan farkı nedir?
random_user_name

26

4
Bu, anahtarlarında boşlukları olan ilişkilendirilebilir diziler ve diziler üzerinde çalışmaz, örn [1, 2, 4 => 3].
Ja͢ck

Üzgünüm bu işe yarayacak. Lütfen bağlantı sağladığım makaleyi okuyun
Airy

4
Olmaz. Yukarıdaki yorumumun dizisini düşünün; değeri kaldırmak için kodunuzu kullandıktan sonra 3dizi olacak [1, 2, 3]; diğer bir deyişle, değer kaldırılmadı. Açık olmak gerekirse, tüm senaryolarda başarısız olduğunu söylemiyorum, sadece bu.
Ja͢ck

1
array_splice en iyi yöntemdir, unset sildikten sonra dizi dizinlerini ayarlamaz
Raaghu

21

Veya basitçe, manuel yolla:

foreach ($array as $key => $value){
    if ($value == $target_value) {
        unset($array[$key]);
    }
}

Bu en güvenli olanıdır, çünkü diziniz üzerinde tam kontrole sahipsiniz.


1
array_splice()Bunun yerine kullanıldığında unset()dizi dizinleri de yeniden sıralanır; bu durumda bu daha iyi olabilir.
Daniele Orlando

20

Aşağıdaki kodla, yinelenen değerler $ iletilerinden kaldırılacaktır.

$messages = array_diff($messages, array(401));


3
Yukarı-oy kullandı. Zaten diğer cevaplar arasındaydı ama bunu en iyi şekilde, basit şekilde tutarak söylüyorsun. Cevap sadece "array_diff" dir
ghbarratt

1
Basit görünüyor ancak karmaşıklığı O (n) 'den O (n lg n)' ye değiştiriyor. Yani, aslında daha karmaşık;)
Krzysztof Przygoda

20

PHP'niz varsa 5.3+, bir satır kodu vardır:

$array = array_filter($array, function ($i) use ($value) { return $i !== $value; }); 

Emin misiniz? Bu kapanışın erişimi yok $value, bu yüzden kapanış içinde erişebilmeniz için gerçekten bir mini sınıfa $value
konulmalıdır

@cale_b, örneği güncelledim. Ayrıca burada referans: php.net/manual/tr/functions.anonymous.php
David Lin

3
Bu "tek satır kodu" olarak adlandırırsanız tüm kod tabanınızı tek bir satıra da yazabilirsiniz
Milan Simek

16
function array_remove_by_value($array, $value)
{
    return array_values(array_diff($array, array($value)));
}

$array = array(312, 401, 1599, 3);

$newarray = array_remove_by_value($array, 401);

print_r($newarray);

Çıktı

Array ( [0] => 312 [1] => 1599 [2] => 3 )


2
Bu çözüm birden fazla işlev çağrısı içerdiğinden, bu daha hızlı olup olmadığından emin değilim.
Julian Paolo Dayag

13

yapabilirsin:

unset($messages[array_flip($messages)['401']]);

Açıklama : 401Diziyi çevirdikten sonra anahtarı olan öğeyi silin .


Devleti korumak istiyorsan çok dikkatli olmalısın. çünkü gelecekteki tüm kodların anahtarlar yerine değerlere sahip olması gerekir.
saadlulu

1
array_flip () orijinal diziyi etkilemediğinden @saadlulu $ messages dizisi çevrilmeyecektir, bu nedenle önceki satırı uyguladıktan sonra ortaya çıkan dizi, istenmeyen sonucun kaldırılması dışında aynı olacaktır.
Qurashi

2
Bunun doğru olup olmadığından emin değilim, değeri olan birkaç öğe varsa ne olur 401?
Zippp

Bu yine de anahtarları koruyacaktır.
Szabolcs Páll

8

Birden çok değeri silmek için şunu deneyin:

while (($key = array_search($del_val, $messages)) !== false) 
{
    unset($messages[$key]);
}

6

Alt çizginin mantığını ödünç aldı.JS _.reject ve iki fonksiyon yarattı (insanlar fonksiyonları tercih ediyor !!)

array_reject_value: Bu işlev belirtilen değeri basitçe reddediyor (PHP4,5,7 için de çalışıyor)

function array_reject_value(array &$arrayToFilter, $deleteValue) {
    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if ($value !== $deleteValue) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

array_reject: Bu işlev sadece çağrılabilir yöntemi reddediyor (PHP> = 5.3 için çalışıyor)

function array_reject(array &$arrayToFilter, callable $rejectCallback) {

    $filteredArray = array();

    foreach ($arrayToFilter as $key => $value) {
        if (!$rejectCallback($value, $key)) {
            $filteredArray[] = $value;
        }
    }

    return $filteredArray;
}

Mevcut örneğimizde yukarıdaki işlevleri aşağıdaki gibi kullanabiliriz:

$messages = [312, 401, 1599, 3, 6];
$messages = array_reject_value($messages, 401);

hatta daha iyi: (bu bize daha iyi bir sözdizimi vermek olarak gibi kullanmak array_filter biri)

$messages = [312, 401, 1599, 3, 6];
$messages = array_reject($messages, function ($value) {
    return $value === 401;
});

Yukarıdakiler, 401'e eşit veya daha büyük olan tüm değerleri kaldırmak istediğimizi varsayalım gibi daha karmaşık şeyler için kullanılabilir:

$messages = [312, 401, 1599, 3, 6];
$greaterOrEqualThan = 401;
$messages = array_reject($messages, function ($value) use $greaterOrEqualThan {
    return $value >= $greaterOrEqualThan;
});

1
Bu yeniden icat eden filtre değil mi? php.net/manual/tr/function.array-filter.php
Richard Duerr

Evet kesinlikle. Zaten yazıda söylediğim gibi "ya da daha iyisi: (Bu bize dizi_filter biri gibi kullanmak için daha iyi bir sözdizimi vermek gibi)". Bazen fonksiyonun alt çizgi olarak reddedilmesi gerekir ve gerçekten filtrenin tam tersidir (ve mümkün olduğunca daha az kodla almanız gerekir). Fonksiyonların yaptığı budur. Bu, değerleri reddetmenin basit bir yoludur.
John Skoumbourdis

6
$array = array("apple", "banana",'mango');
$array = array_filter($array, function($v) { return $v != "apple"; });

Bunu deneyin, Öğeyi değere göre kaldırmanın en iyi ve en hızlı yolu


5

@Bojangles cevabı bana yardımcı oldu. Teşekkür ederim.

Benim durumumda, dizi ilişkilendirilebilir veya değil olabilir, bu yüzden aşağıdaki işlevi ekledi

function test($value, $tab) {

 if(($key = array_search($value, $tab)) !== false) {
    unset($tab[$key]); return true;

 } else if (array_key_exists($value, $tab)){
        unset($tab[$value]); return true;

 } else {
    return false; // the $value is not in the array $tab
 }

}

Saygılarımızla


4

tek satırlık kod ( array_diff () sayesinde ) aşağıdakileri kullanın:

$messages = array_diff($messages, array(401));

4

Kabul edilen cevap diziyi ilişkisel diziye dönüştürür, bu nedenle, kabul edilen cevabı ile ilişkisel olmayan bir dizi olarak tutmak isterseniz, bunu da kullanmanız gerekebilir array_values.

if(($key = array_search($del_val, $messages)) !== false) {
    unset($messages[$key]);
    $arr = array_values($messages);
}

Referans burada


4

İhtiyacınıza göre , dizinizde benzersiz değerleri tutmak istiyorsanız, " her değer yalnızca bir kez olabilir ", ardındanarray_unique() aradığınız şey olabilir.

Giriş:

$input = array(4, "4", "3", 4, 3, "3");
$result = array_unique($input);
var_dump($result);

Sonuç:

array(2) {
  [0] => int(4)
  [2] => string(1) "3"
}

4

Silmek istediğiniz değerler bir dizideyse veya olabiliyorsa. Array_diff işlevini kullanın . Böyle şeyler için harika çalışıyor gibi görünüyor.

array_diff

$arrayWithValuesRemoved = array_diff($arrayOfData, $arrayOfValuesToRemove);

1
Bunun bu cevaptan farkı nedir?
random_user_name

4

Bunun hiç etkili olmadığını biliyorum ama basit, sezgisel ve okunması kolay.
Birisi daha fazla değer veya daha spesifik koşullarla çalışmak için genişletilebilecek kadar süslü olmayan bir çözüm arıyorsa .. İşte basit bir kod:

$result = array();
$del_value = 401;
//$del_values = array(... all the values you don`t wont);

foreach($arr as $key =>$value){
    if ($value !== $del_value){
        $result[$key] = $value;
    }

    //if(!in_array($value, $del_values)){
    //    $result[$key] = $value;
    //}

    //if($this->validete($value)){
    //      $result[$key] = $value;
    //}
}

return $result

4

Dizi anahtarını ile alın array_search().


2
IF değerini nasıl silerim ve yalnızca array_search ile bulursam?
Adam Strudwick

3
$ k = dizi_search ($ iğne, $ samanlık, doğru); if ($ k! == false) {unset ($ haystack [$ k]); }
evan

3

Eğer anahtarını bilmiyorsanız bunun bir önemi yok demektir.

Değeri anahtar olarak yerleştirebilirsiniz, bu değeri anında bulacağı anlamına gelir. Tüm öğelerde aramayı tekrar tekrar kullanmaktan daha iyidir.

$messages=array();   
$messages[312] = 312;    
$messages[401] = 401;   
$messages[1599] = 1599;   
$messages[3] = 3;    

unset($messages[3]); // no search needed

Yalnızca bir dizeye dönüştürülebilen nesneler için çalışır.
Emile Bergeron

2

orOperatörü kullanan bir astar :

($key = array_search($del_val, $messages)) !== false or unset($messages[$key]);

2

bu URL'ye başvurabilirsiniz : işlev için

array-diff-key()

<?php
$array1 = array('blue'  => 1, 'red'  => 2, 'green'  => 3, 'purple' => 4);
$array2 = array('green' => 5, 'blue' => 6, 'yellow' => 7, 'cyan'   => 8);

var_dump(array_diff_key($array1, $array2));
?>

Sonra çıktı,

array(2) {
  ["red"]=>
  int(2)
  ["purple"]=>
  int(4)
}


1

Ben en basit yolu bir foreach döngü ile bir işlevi kullanmak olacağını düşünüyorum:

//This functions deletes the elements of an array $original that are equivalent to the value $del_val
//The function works by reference, which means that the actual array used as parameter will be modified.

function delete_value(&$original, $del_val)
{
    //make a copy of the original, to avoid problems of modifying an array that is being currently iterated through
    $copy = $original;
    foreach ($original as $key => $value)
    {
        //for each value evaluate if it is equivalent to the one to be deleted, and if it is capture its key name.
        if($del_val === $value) $del_key[] = $key;
    };
    //If there was a value found, delete all its instances
    if($del_key !== null)
    {
        foreach ($del_key as $dk_i)
        {
            unset($original[$dk_i]);
        };
        //optional reordering of the keys. WARNING: only use it with arrays with numeric indexes!
        /*
        $copy = $original;
        $original = array();
        foreach ($copy as $value) {
            $original[] = $value;
        };
        */
        //the value was found and deleted
        return true;
    };
    //The value was not found, nothing was deleted
    return false;
};

$original = array(0,1,2,3,4,5,6,7,4);
$del_val = 4;
var_dump($original);
delete_value($original, $del_val);
var_dump($original);

Çıktı:

array(9) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [4]=>
  int(4)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
  [8]=>
  int(4)
}
array(7) {
  [0]=>
  int(0)
  [1]=>
  int(1)
  [2]=>
  int(2)
  [3]=>
  int(3)
  [5]=>
  int(5)
  [6]=>
  int(6)
  [7]=>
  int(7)
}

1

PHP 7.4 ile ok fonksiyonlarını kullanma:

$messages = array_filter($messages, fn ($m) => $m != $del_val);

İlişkili olmayan bir dizi olarak tutmak için aşağıdakilerle sarın array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
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.