Usuń tablicę PHP według wartości (nie klucza)

885

Mam tablicę PHP w następujący sposób:

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

Chcę usunąć element zawierający wartość $del_val(na przykład $del_val=401), ale nie znam jego klucza. Może to pomóc: każda wartość może być tam tylko raz .

Proszę o najprostszą funkcję do wykonania tego zadania.

Adam Strudwick
źródło
1
@Adam Strudwick Ale jeśli masz wiele usunięć z tej tablicy, czy lepiej byłoby powtórzyć ją raz i uczynić jej klucz identycznym z wartością?
dzona
To samo pytanie: stackoverflow.com/questions/1883421/...
Eric Lavoie
możliwy duplikat PHP Usuń element z tablicy
Alex

Odpowiedzi:

1565

Używając array_search()i unset, spróbuj wykonać następujące czynności:

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

array_search()zwraca klucz znalezionego elementu, którego można użyć do usunięcia tego elementu z oryginalnej tablicy za pomocą unset(). Wróci FALSEpo awarii, jednak w przypadku sukcesu może zwrócić wartość fałsz-y ( 0na przykład kluczem ), dlatego !==używany jest operator ścisłego porównania .

if()Oświadczenie sprawdzi, czy array_search()zwrócony wartość i będzie wykonywać jedynie działania, jeśli tak się stało.

Bojangles
źródło
14
Czy $ messages = array_diff ($ messages, array ($ del_val)) też działałoby? Czy byłby lepszy w działaniu?
Adam Strudwick,
9
@Adam Dlaczego nie przetestować? Mam wrażenie, że array_diff()byłoby wolniej, ponieważ porównuje dwie tablice, a nie tylko przeszukuje jedną podobną array_search().
Bojangles,
22
Mimo że jest to poprawne, należy unikać przypisywania wartości w takich instrukcjach. Doprowadzi cię to tylko do kłopotów.
adlawson,
17
Co jeśli $keyjest 0?
evan
16
Jeśli 0szukana wartość ma klucz lub inną wartość falsey, nie rozbroi tej wartości, a kod nie będzie działał. Powinieneś przetestować $key === false. (edytuj - masz to)
evan
671

Cóż, usunięcie elementu z tablicy jest w zasadzie tylko różnicą dla jednego elementu.

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

Ładnie się uogólnia, jeśli chcesz, możesz jednocześnie usunąć tyle elementów, ile chcesz.

Uwaga: Zauważ, że moje rozwiązanie tworzy nową kopię tablicy, zachowując starą nietkniętą w przeciwieństwie do przyjętej odpowiedzi, która mutuje. Wybierz ten, którego potrzebujesz.

Rok Kralj
źródło
32
działa to tylko w przypadku obiektów, które można przekonwertować na ciąg znaków
nischayn22,
7
Wydaje mi się, że pojawia się „Błąd analizy”, mówiąc [$element], użyłem array($element)zamiast tego. Żaden biggie, ale chciał tylko, aby każdy, kto miał podobny problem, wiedział, że nie był sam
Angad
8
Jasne, założyłem, że PHP 5.4 ma teraz większość porzucenia starej notacji. Dziękuję za uwagę.
Rok Kralj
22
Warto zauważyć, że z jakiegoś powodu array_diffużywa (string) $elem1 === (string) $elem2jako warunku równości, a nie $elem1 === $elem2jak można się spodziewać. Problem wskazany przez @ nischayn22 jest tego konsekwencją. Jeśli chcesz użyć czegoś jako funkcji narzędzia, która będzie działać dla tablic dowolnych elementów (które mogą być obiektami), odpowiedź Bojangle może być lepsza z tego powodu.
Mark Amery
4
Zauważ również, że ta metoda wykonuje sortowanie wewnętrznie dla każdego argumentu, array_diff()a zatem przesuwa środowisko wykonawcze do O (n lg n) z O (n).
Ja͢ck
115

Ciekawym sposobem jest użycie array_keys():

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

array_keys()Funkcja przyjmuje dwa dodatkowe parametry, aby wrócić tylko klucze do określonej wartości i czy wymagana jest ścisła kontrola (czyli używając === dla porównania).

Może to również usunąć wiele elementów tablicy o tej samej wartości (np [1, 2, 3, 3, 4].).

Jacek
źródło
3
@ blasteralfredΨ Wyszukiwanie liniowe to O (n); Nie jestem pewien, dlaczego wydaje ci się, że to problem.
Ja͢ck
1
Tak, jest to skuteczne przy wyborze wielu elementów / kluczy tablicy.
Oki Erie Rinaldi
3
Jest to najlepsze rozwiązanie dla tablic, które mogą nie zawierać wszystkich unikalnych wartości.
Derokorian
Problem polega na tym, że pozostawia on indeks kluczy po kolei: [0] - a, [2] - b ([1] zniknął, ale tablica wciąż go nie ma)
Rodniko
3
@Rodniko, w którym to przypadku również będziesz potrzebować array_values(); pozostałe klucze są nadal w tej samej kolejności, więc technicznie nie jest to „nieposortowane”
Ja͢ck
55

Jeśli wiesz na pewno, że tablica będzie zawierała tylko jeden element o tej wartości, możesz to zrobić

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

Jeśli jednak twoja wartość może wystąpić więcej niż jeden raz w tablicy, możesz to zrobić

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

Uwaga: druga opcja działa tylko dla PHP 5.3 + z zamknięciami

adlawson
źródło
41
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);
Rmannn
źródło
11
Działa to tylko wtedy, gdy tablica nie zawiera zduplikowanych wartości innych niż te, które próbujesz usunąć.
jberculo
2
@jberculo, a czasem dokładnie to, czego potrzebujesz, w niektórych przypadkach oszczędza mi robienie tablicy unikatowej na nim aswel
DarkMukke
Może, ale użyłbym do tego specjalnie zaprojektowanych funkcji, zamiast być tylko szczęśliwym efektem ubocznym funkcji, która jest zasadniczo używana i przeznaczona do czegoś innego. Sprawiłoby to również, że Twój kod byłby mniej przejrzysty.
jberculo
Komunikat mówi „każda wartość może być tam tylko raz”, to powinno działać. Byłoby miło, gdyby plakat użył nazw zmiennych smae i dodał trochę wyjaśnień
Raatje
2
najwyraźniej jest to najszybszy w porównaniu do wybranego rozwiązania, zrobiłem małe testy porównawcze.
AMB,
28

Spójrz na następujący kod:

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

Możesz to zrobić:

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

I to da ci tę tablicę:

array('nice_item', 'another_liked_item')
theCodeMachine
źródło
1
W przypadku tablic asocjacyjnych należy użyć array_diff_assoc ()
theCodeMachine
5
Czym różni się to od tej odpowiedzi ?
random_user_name
26

Najlepszym sposobem jest array_splice

array_splice($array, array_search(58, $array ), 1);

Powód najlepszego znajduje się tutaj: http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/

Przewiewny
źródło
4
Nie zadziała to na tablicach asocjacyjnych i tablicach, które mają luki w swoich kluczach, np [1, 2, 4 => 3].
Ja͢ck
Nie przepraszam, to zadziała. Proszę przeczytać artykuł, który podałem link
Airy
4
Nie będzie. Rozważ tablicę mojego powyższego komentarza; kiedy użyję twojego kodu do usunięcia wartości 3, tablica będzie [1, 2, 3]; innymi słowy, wartość nie została usunięta. Żeby było jasne, nie mówię, że zawodzi we wszystkich scenariuszach, tylko w tym jednym.
Ja͢ck
1
array_splice to najlepsza metoda, unset nie zmieni indeksów tablicy po usunięciu
Raaghu
21

Lub po prostu ręczny sposób:

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

Jest to najbezpieczniejszy z nich, ponieważ masz pełną kontrolę nad tablicą

Victor Priceputu
źródło
1
Użycie array_splice()zamiast unset()spowoduje zmianę kolejności indeksów tablic, co może być lepsze w tym przypadku.
Daniele Orlando,
20

Poniższy kod spowoduje, że powtarzające się wartości zostaną usunięte z wiadomości $.

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

Syed Abidur Rahman
źródło
3
Podwyższony głos. Było już wśród innych odpowiedzi, ale mówisz to najlepiej, utrzymując prostotę, tak jak masz. Odpowiedź brzmi: „array_diff”
ghbarratt
1
Wygląda prosto, ale zmienia złożoność z O (n) na O (n lg n). Tak więc jest to bardziej skomplikowane;)
Krzysztof Przygoda
20

Jeśli masz PHP 5.3+, jest jeden kod wiersza:

$array = array_filter($array, function ($i) use ($value) { return $i !== $value; }); 
David Lin
źródło
Jesteś pewny? To zamknięcie nie ma dostępu $value, więc naprawdę musi zostać umieszczone w mini klasie, abyś mógł uzyskać dostęp $valuew zamknięciu ....
random_user_name
@cale_b, zaktualizowałem przykład. Oto także ref: php.net/manual/en/functions.anonymous.php
David Lin
3
Równie dobrze możesz napisać całą bazę kodu na jednej linii, jeśli nazwiesz ten „kodem jednej linii”
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);

Wynik

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

tttony
źródło
2
nie jestem pewien, czy jest to szybsze, ponieważ to rozwiązanie obejmuje wiele wywołań funkcji.
Julian Paolo Dayag,
13

możesz to zrobić:

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

Objaśnienie : Usuń element, który ma klucz 401po odwróceniu tablicy.

Qurashi
źródło
Musisz być bardzo ostrożny, jeśli chcesz zachować stan. ponieważ cały przyszły kod będzie musiał mieć wartości zamiast kluczy.
saadlulu
1
Tablica @saadlulu $ messages nie zostanie odwrócona, ponieważ array_flip () nie wpływa na oryginalną tablicę, więc tablica wynikowa po zastosowaniu poprzedniej linii będzie taka sama, z tym że niechciany wynik zostanie usunięty.
Qurashi
2
nie jestem pewien, czy jest to poprawne, co jeśli jest kilka elementów o wartości 401?
Zippp,
To nadal zachowa klucze.
Szabolcs Páll
8

Aby usunąć wiele wartości, spróbuj tego:

while (($key = array_search($del_val, $messages)) !== false) 
{
    unset($messages[$key]);
}
Rajendra Khabiya
źródło
6

Zapożyczył logikę podkreślenia.JS _.reject i utworzył dwie funkcje (ludzie wolą funkcje !!)

array_reject_value: Ta funkcja po prostu odrzuca podaną wartość (działa również dla PHP4,5,7)

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

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

    return $filteredArray;
}

array_reject: Ta funkcja po prostu odrzuca metodę wywoływania (działa dla PHP> = 5.3)

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

    $filteredArray = array();

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

    return $filteredArray;
}

W naszym obecnym przykładzie możemy użyć powyższych funkcji w następujący sposób:

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

lub nawet lepiej: (ponieważ daje nam to lepszą składnię do użycia jak na przykład array_filter )

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

Powyższe może być użyte do bardziej skomplikowanych rzeczy, takich jak powiedzmy, że chcielibyśmy usunąć wszystkie wartości, które są większe lub równe 401, moglibyśmy to po prostu zrobić:

$messages = [312, 401, 1599, 3, 6];
$greaterOrEqualThan = 401;
$messages = array_reject($messages, function ($value) use $greaterOrEqualThan {
    return $value >= $greaterOrEqualThan;
});
John Skoumbourdis
źródło
1
Czy to nie jest nowy filtr? php.net/manual/en/function.array-filter.php
Richard Duerr
W rzeczy samej. Jak już mówię w poście „lub nawet lepiej: (ponieważ daje nam to lepszą składnię, taką jak w przypadku argumentu array_filter)”. Czasami naprawdę musisz po prostu mieć funkcję odrzucania jako podkreślenia i jest to naprawdę przeciwieństwo filtru (i musisz uzyskać ją z jak najmniejszą ilością kodu). To właśnie robią funkcje. Jest to prosty sposób na odrzucenie wartości.
John Skoumbourdis,
6
$array = array("apple", "banana",'mango');
$array = array_filter($array, function($v) { return $v != "apple"; });

Spróbuj tego, jest to najlepszy i najszybszy sposób na usunięcie elementu według wartości

Paras Raiyani
źródło
5

Odpowiedź @Bojangles pomogła mi. Dziękuję Ci.

W moim przypadku tablica może być asocjacyjna lub nie, więc dodałem następującą funkcję

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
 }

}

pozdrowienia

angeltcho
źródło
4

pojedynczy kod liniowy (dzięki array_diff () ), użyj następującego:

$messages = array_diff($messages, array(401));
Gwiazda
źródło
4

Zaakceptowana odpowiedź konwertuje tablicę na tablicę asocjacyjną, więc jeśli chcesz zachować ją jako tablicę niepowiązaną z zaakceptowaną odpowiedzią, być może będziesz musiał użyć array_valuesrównież.

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

Referencje są tutaj

SaidbakR
źródło
4

Zgodnie z twoim wymaganiem „ każda wartość może istnieć tylko raz ”, jeśli chcesz zachować unikalne wartości w tablicy, array_unique()może być tym, czego szukasz.

Wejście:

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

Wynik:

array(2) {
  [0] => int(4)
  [2] => string(1) "3"
}
Mohd Abdul Mujib
źródło
4

Jeśli wartości, które chcesz usunąć, są lub mogą znajdować się w tablicy. Użyj funkcji array_diff . Wydaje się, że działa świetnie na takie rzeczy.

array_diff

$arrayWithValuesRemoved = array_diff($arrayOfData, $arrayOfValuesToRemove);
użytkownik1518699
źródło
1
Czym różni się to od tej odpowiedzi ?
random_user_name
4

Wiem, że to wcale nie jest wydajne, ale jest proste, intuicyjne i łatwe do odczytania.
Jeśli więc ktoś szuka nie tak wymyślnego rozwiązania, które można rozszerzyć do pracy z większymi wartościami lub bardziej szczegółowymi warunkami ... oto prosty 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
d.raev
źródło
4

Uzyskaj klucz tablicy za pomocą array_search().

evan
źródło
2
Jak usunąć wartość JEŻELI i tylko wtedy, gdy znajdę ją za pomocą tablicy_wyszukiwania?
Adam Strudwick
3
$ k = array_search ($ igła, $ stóg siana, prawda); if ($ k! == false) {unset ($ stóg siana [$ k]); }
evan
3

Jeśli nie znasz jego klucza, oznacza to, że to nie ma znaczenia.

Możesz umieścić wartość jako klucz, co oznacza, że ​​natychmiast znajdzie wartość. Lepsze niż wyszukiwanie we wszystkich elementach w kółko.

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

unset($messages[3]); // no search needed
Ismael
źródło
Działa tylko w przypadku obiektów, które można przekonwertować na ciąg.
Emile Bergeron,
2

One-liner z oroperatorem:

($key = array_search($del_val, $messages)) !== false or unset($messages[$key]);
Eric
źródło
2

możesz odwołać się do tego adresu URL : dla funkcji

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

Zatem wyjście powinno być

array(2) {
  ["red"]=>
  int(2)
  ["purple"]=>
  int(4)
}
manish1706
źródło
1

Myślę, że najprostszym sposobem byłoby użycie funkcji z pętlą foreach:

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

Dane wyjściowe będą:

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)
}
algo
źródło
1

W PHP 7.4 za pomocą funkcji strzałek:

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

Aby zachować tablicę niesocjacyjną, zawiń ją array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
Roy
źródło