1144

I have a PHP array as follows:

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

I want to delete the element containing the value $del_val (for example, $del_val=401), but I don't know its key. This might help: each value can only be there once.

I'm looking for the simplest function to perform this task, please.

Star
  • 3,222
  • 5
  • 32
  • 48
Adam Strudwick
  • 12,671
  • 13
  • 31
  • 41
  • 1
    @Adam Strudwick But if you have many deletions on this array, would it be better to iterate it once and make its key same as value? – dzona Nov 14 '13 at 09:00
  • 1
    Same question : http://stackoverflow.com/questions/1883421/removing-array-item-by-value – Eric Lavoie Jun 29 '16 at 18:28
  • posible duplicate of [PHP Delete an element from an array](https://stackoverflow.com/questions/2448964/php-how-to-remove-specific-element-from-an-array) – Alex Feb 12 '18 at 07:34

21 Answers21

1972

Using array_search() and unset, try the following:

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

array_search() returns the key of the element it finds, which can be used to remove that element from the original array using unset(). It will return FALSE on failure, however it can return a false-y value on success (your key may be 0 for example), which is why the strict comparison !== operator is used.

The if() statement will check whether array_search() returned a value, and will only perform an action if it did.

Orwellophile
  • 13,235
  • 3
  • 69
  • 45
Bojangles
  • 99,427
  • 50
  • 170
  • 208
  • 17
    Would $messages = array_diff($messages, array($del_val)) work too? Would it be better in performance? – Adam Strudwick Aug 29 '11 at 00:55
  • 10
    @Adam Why not test it out? My feeling is that `array_diff()` would be slower as it's _comparing two_ arrays, not simply searching through _one_ like `array_search()`. – Bojangles Aug 29 '11 at 00:57
  • 26
    Even though this is valid, you should avoid assigning values in statements like that. It will only get you into trouble. – adlawson Aug 29 '11 at 01:05
  • 2
    @adam Exactly what @evan said. If the `key = 0` for the $del_val, you will not unset it. Also, it can be very difficult to maintain such assignments. – adlawson Aug 29 '11 at 01:09
  • I've amended my answer; the `!==` false will check for the return type now, too. @Adam, please change _your_ code to prevent any errors you might get in the future. – Bojangles Aug 29 '11 at 01:11
  • 17
    If the value you're searching for has a key of `0` or any other falsey value, it won't unset the value and your code won't work. You should test `$key === false`. (edit- you got it) – evan Aug 29 '11 at 01:11
  • @evan My answer's been changed. Thank you for pointing this issue out, as well as the Interslap in the form of -2 rep. – Bojangles Aug 29 '11 at 01:13
  • 6
    Note that this will not reset array keys. – montrealist Mar 08 '13 at 05:29
  • +1 for strict comparison. I just had a case where my found key was `0`. – Hannes Schneidermayer Jun 12 '14 at 07:39
  • 1
    For >php5.3 : $array = array_filter($array, function($i){return $i != $value;}); – David Lin Jul 08 '14 at 03:43
  • To catch keys that are 0, the following syntax works: if(FALSE !== $nullKey = array_search($del_val, $messages)){ ... } – Pez Mar 03 '15 at 00:46
  • 3
    Just tried it with an array with five 0 values and the code above removed just the first 0 element (with index=0), while the other elements with indexes 1, 2, 3 & 4 remained. – PrestaShopDeveloper Apr 20 '15 at 09:10
  • 3
    If you need to reorder the keys then change `unset` to `array_splice`. `array_splice($messages, $key, 1);` – Thomas Wood Aug 26 '16 at 01:46
  • it should be `array_search($value, $array, false)` to catch also matches where without variable type matching. Ex. `"123" == 123` – powtac Nov 22 '16 at 14:19
  • @adlawson It's a pretty standard thing to do. But doing a comparison on it at the same time like is done in this answer is ugly and i'd shift it out. – Andrew May 19 '17 at 20:14
  • 2
    I think this shuold be done in a while loop because the value can occur multiple times. – Jakob Alexander Eichler Feb 16 '18 at 09:34
  • Your code will fail if array_search find value at key 0 then variable $key will evoluate to true and then unset($message[$key]) will be unset($message[true]) this will unset random key.. – Sider Topalov Jul 13 '18 at 13:05
  • If you want this to work with associative arrays and remove also multiple values, the just replace the "if" with "while" for a more generic approach: while (($key = array_search($value, $data)) !== false) { unset($data[ $key ]); } – klodoma Nov 04 '19 at 20:31
  • 1
    To remove all instances not just the first found element we could use **while** `while (($key = array_search($del_val, $messages)) !== false) { unset($messages[$key]); }` – Alexandru Burca Jul 14 '20 at 21:41
  • 1
    Note that this and `array_filter` will result in an array without incremental keys, so if it's JSON encoded it will be converted to an object. To avoid this use `array_values` after. – nick Jul 26 '20 at 18:40
902

Well, deleting an element from array is basically just set difference with one element.

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

It generalizes nicely, you can remove as many elements as you like at the same time, if you want.

Disclaimer: Note that my solution produces a new copy of the array while keeping the old one intact in contrast to the accepted answer which mutates. Pick the one you need.

Rok Kralj
  • 46,826
  • 10
  • 71
  • 80
  • 38
    this only works for objects that can be converted to a string – nischayn22 Aug 12 '12 at 20:20
  • 8
    I seem to be getting a 'Parse Error' for saying `[$element]`, I used `array($element)` instead. No biggie, but just wanted anyone who had a similar issue to know that they weren't alone – Angad Aug 26 '13 at 14:11
  • 9
    Sure, I have assumed PHP 5.4 is now in majority to drop the old notation. Thanks for the remark. – Rok Kralj Aug 26 '13 at 18:57
  • 27
    It's worth noting that for some reason `array_diff` uses `(string) $elem1 === (string) $elem2` as its equality condition, not `$elem1 === $elem2` as you might expect. The issue pointed out by @nischayn22 is a consequence of this. If you want something to use as a utility function that will work for arrays of arbitrary elements (which might be objects), Bojangle's answer might be better for this reason. – Mark Amery Jan 01 '14 at 22:39
  • 6
    Also note that this method performs a sort internally for each argument to `array_diff()` and thus nudges the runtime up to O(n lg n) from O(n). – Ja͢ck Jul 14 '14 at 06:12
  • I don't know why, but the `[$element]` in square brackets breaks my code, while `array($element)` is working. – Karl Adler Dec 19 '14 at 11:40
  • For force accept string, int or array, the way is: `return array_diff($array (array)$element)` – Wallace Vizerra Apr 09 '15 at 20:00
  • 1
    the best and cleanest solution - don't know why it's not accepted. done with plain and native php functions. – Gummibeer Nov 04 '15 at 14:45
  • Why create a separate function for one php function? This is overkill because you can just call array_diff directly with the same params. – randomizer Dec 17 '15 at 08:36
  • It's a way slower than array_search. See @Jack comment: it changes complexity from O(n) to O(n lg n), i.e. for 1000 elements this solution will take ~7 times more cpu time than array_search. – Krzysztof Przygoda Dec 20 '15 at 19:32
  • @KrzysztofPrzygoda: He doesn't know what he is talking about. The complexity of this functions is IMPLEMENTATION and VERSION dependant. – Rok Kralj Dec 21 '15 at 11:28
  • I agree with Krzysztof Przygoda, this function is **two orders of magnitude** slower than array_search() with 2554 real-world elements. – dotancohen Apr 20 '16 at 09:36
  • to be sure it is iterable use array_values(array_diff($arr1, $arr2)); – Tertium Mar 31 '17 at 20:25
  • This creates a new array. Isn't this a drawback compared to the `unset` solution? – robsch Nov 02 '17 at 10:40
  • Doesn't work for me: I use it on an array with 2 elements while the first element will be removed but the elements keep their index but seems to be unreadable: Notice: Undefined offset: 0 – Jonny May 22 '18 at 14:29
  • 1
    That was helpful for me: `$alphabet = range('A', 'Z'); $allowedLetters = array_diff($alphabet, ['Q', 'X', 'Y', 'Z']);` – Ryan Oct 12 '18 at 14:56
173

One interesting way is by using array_keys():

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

The array_keys() function takes two additional parameters to return only keys for a particular value and whether strict checking is required (i.e. using === for comparison).

This can also remove multiple array items with the same value (e.g. [1, 2, 3, 3, 4]).

d-_-b
  • 21,536
  • 40
  • 150
  • 256
Ja͢ck
  • 170,779
  • 38
  • 263
  • 309
73

If you know for definite that your array will contain only one element with that value, you can do

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

If, however, your value might occur more than once in your array, you could do this

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

Note: The second option only works for PHP5.3+ with Closures

d-_-b
  • 21,536
  • 40
  • 150
  • 256
adlawson
  • 6,303
  • 1
  • 35
  • 46
50
$fields = array_flip($fields);
unset($fields['myvalue']);
$fields = array_flip($fields);
Rmannn
  • 1,335
  • 1
  • 13
  • 18
  • 15
    This only works when your array does not contain duplicate values other than the ones you're trying to remove. – jberculo Jun 02 '14 at 08:35
  • 3
    @jberculo and sometimes that exactly what you need, in some cases it saves me doing a array unique on it aswel – DarkMukke Nov 14 '14 at 15:06
  • Maybe, but I would use functions specifically designed to do that, instead of being just a fortunate side effect of a function that is basically used and intended for something else. It would also make your code less transparent. – jberculo Nov 14 '14 at 16:08
  • The message states "each value can only be there once" this should work. It would have been nice if the poster had used the smae variable names though and added a little explenation – Raatje Sep 24 '15 at 08:37
  • This solution was helpful for me because I had already made the array unique and did not care about the keys—only the values that had been returned by previous mutations. – JessycaFrederick Aug 21 '16 at 21:54
  • 2
    apparently this is fastest as compared to selected solution, i did small benchmarking. –  Oct 20 '17 at 08:35
  • **NOT RECOMMENDED** as other comment says. – T.Todua Apr 18 '20 at 20:28
35

The Best way is array_splice

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

Reason for Best is here at http://www.programmerinterview.com/index.php/php-questions/how-to-delete-an-element-from-an-array-in-php/

Airy
  • 5,484
  • 7
  • 53
  • 78
  • 6
    This will not work on associative arrays and arrays that have gaps in their keys, e.g. `[1, 2, 4 => 3]`. – Ja͢ck Jul 14 '14 at 06:27
  • No sorry this will work. Please read the article I have provided link – Airy Jul 15 '14 at 12:05
  • 6
    It won't. Consider the array of my above comment; after I use your code to remove the value `3`, the array will be `[1, 2, 3]`; in other words, the value wasn't removed. To be clear, I'm not saying it fails in all scenarios, just this one. – Ja͢ck Jul 15 '14 at 12:10
  • 1
    array_splice is the best method, unset will not adjust the array indexes after deleting – Raaghu Nov 07 '15 at 14:23
  • Not a good solution. If you'll search for the value that doesn't exists: array_search will return "false", and array_splice will turn it into 0 and will remove first element in array. $array = [3344, 4455, 5566]; array_splice($array, array_search(1122, $array), 1); // as result $array = [4455, 5566] – sNICkerssss Jul 14 '23 at 09:04
33

With PHP 7.4 using arrow functions:

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

To keep it a non-associative array wrap it with array_values():

$messages = array_values(array_filter($messages, fn ($m) => $m != $del_val));
Roy
  • 4,254
  • 5
  • 28
  • 39
  • This is awesome. Easy to understand, practical use of arrow functions which are new to me. I needed to remove part of an array of associative arrays based on a nested value which isn't really possible with any of the other answers. I had resorted to using a `foreach()` loop, but this is much more concise. – But those new buttons though.. Jan 12 '22 at 04:21
32

Or simply, manual way:

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

This is the safest of them because you have full control on your array

T.Todua
  • 53,146
  • 19
  • 236
  • 237
19
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);

Output

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

tttony
  • 4,944
  • 4
  • 26
  • 41
  • 2
    i'm not sure if this is faster since this solution involves multiple function calls. – Julian Paolo Dayag Nov 18 '16 at 06:56
  • 2
    Code-only answers are low-value on Stack Overflow. Every answer should include an explanation of how it works or why you feel it is good advice versus other techniques. – mickmackusa Jun 30 '20 at 07:33
16

you can do:

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

Explanation: Delete the element that has the key 401 after flipping the array.

Star
  • 3,222
  • 5
  • 32
  • 48
Qurashi
  • 1,449
  • 16
  • 27
  • You have to be very careful if you want to preserve the state. because all future code will have to have values instead of keys. – saadlulu Jun 30 '15 at 13:18
  • 2
    @saadlulu $messages array will not be flipped since array_flip() does not effect the original array, so the resulting array after applying the previous line will be the same except that the unwanted result will be removed. – Qurashi Jun 30 '15 at 18:46
  • 3
    not sure if this is correct, what if there are several elements with the value of `401`? – Zippp Mar 06 '19 at 14:54
  • This will still preserve keys. – Szabolcs Páll Apr 08 '20 at 07:15
12

The accepted answer converts the array to associative array, so, if you would like to keep it as a non-associative array with the accepted answer, you may have to use array_values too.

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

The reference is linked here

SaidbakR
  • 13,303
  • 20
  • 101
  • 195
12

PHP 7.4 or above

function delArrValues(array $arr, array $remove) {
    return array_filter($arr, fn($e) => !in_array($e, $remove));
};

So, if you have the array as

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

and you want to remove both 3, 312 from the $messages array, You'd do this

delArrValues($messages, [3, 312])

It would return

[401, 1599]

The best part is that you can filter multiple values easily, even there are multiple occurrences of the same value.

Koushik Das
  • 9,678
  • 3
  • 51
  • 50
  • 1
    Note that an expanded form of the `array_filter` version could be used on older versions of php, such as: ` array_filter( $arr, function($arg) use ($black_list) { return !in_array($arg, $black_list); } ); ` – Mauro Colella Mar 10 '22 at 06:01
8

To delete multiple values try this one:

while (($key = array_search($del_val, $messages)) !== false) 
{
    unset($messages[$key]);
}
Star
  • 3,222
  • 5
  • 32
  • 48
Rajendra Khabiya
  • 1,990
  • 2
  • 22
  • 39
  • 4
    This will be less efficient than looping over the input one time (and there are multiple tools for doing this). Imagine you are iterating an indexed array with 10 elements and you want to remove the elements at index 4 and 8. This will iterate from 0 to 4, then unset element [4], then it will iterate 0 to 8, then unset element [8]. See how this technique will needlessly check [0], [1], [2], [3] more than once. I would never use this technique for any reason and I recommend that all researchers take a wide birth from this answer. (this is the reason for my DV) – mickmackusa Jun 30 '20 at 05:53
7

If you don't know its key it means it doesn't matter.

You could place the value as the key, it means it will instantly find the value. Better than using searching in all elements over and over again.

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

unset($messages[3]); // no search needed
Star
  • 3,222
  • 5
  • 32
  • 48
Ismael
  • 2,330
  • 1
  • 25
  • 37
6

Borrowed the logic of underscore.JS _.reject and created two functions (people prefer functions!!)

array_reject_value: This function is simply rejecting the value specified (also works for 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: This function is simply rejecting the callable method (works for 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;
}

So in our current example we can use the above functions as follows:

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

or even better: (as this give us a better syntax to use like the array_filter one)

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

The above can be used for more complicated stuff like let's say we would like to remove all the values that are greater or equal to 401 we could simply do this:

$messages = [312, 401, 1599, 3, 6];
$greaterOrEqualThan = 401;
$messages = array_reject($messages, function ($value) use $greaterOrEqualThan {
    return $value >= $greaterOrEqualThan;
});
Star
  • 3,222
  • 5
  • 32
  • 48
John Skoumbourdis
  • 3,041
  • 28
  • 34
  • 3
    Isn't this reinventing filter? http://php.net/manual/en/function.array-filter.php – Richard Duerr Oct 25 '16 at 15:50
  • Yes indeed. As I am already saying at the post "or even better: (as this give us a better syntax to use like the array_filter one)". Sometimes you really just need to have the function reject as underscore and it is really just the opposite of the filter (and you need to get it with as less code as possible). This is what the functions are doing. This is a simple way to reject values. – John Skoumbourdis Oct 25 '16 at 17:12
4

A one-liner using the or operator:

($key = array_search($del_val, $messages)) !== false or unset($messages[$key]);
Star
  • 3,222
  • 5
  • 32
  • 48
Eric
  • 95,302
  • 53
  • 242
  • 374
4

I know this is not efficient at all but is simple, intuitive and easy to read.
So if someone is looking for a not so fancy solution which can be extended to work with more values, or more specific conditions .. here is a simple code:

$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
Star
  • 3,222
  • 5
  • 32
  • 48
d.raev
  • 9,216
  • 8
  • 58
  • 79
1

As per your requirement "each value can only be there for once" if you are just interested in keeping unique values in your array, then the array_unique() might be what you are looking for.

Input:

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

Result:

array(2) {
  [0] => int(4)
  [2] => string(1) "3"
}
Star
  • 3,222
  • 5
  • 32
  • 48
Mohd Abdul Mujib
  • 13,071
  • 8
  • 64
  • 88
0

I think the simplest way would be to use a function with a foreach loop:

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

Output will be:

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
  • 108
  • 1
  • 11
0

here is one simple but understandable solution:

$messagesFiltered = [];
foreach ($messages as $message) {
    if (401 != $message) {
        $messagesFiltered[] = $message;
    }
}
$messages = $messagesFiltered;
fico7489
  • 7,931
  • 7
  • 55
  • 89
0

Using array_filter and anonymous function:

$messages = array_filter($messages, function ($value) use ($del_val) {
    return $value != $del_val;
});

You can run a code example here: https://onlinephp.io/c/4f320

Alexxus
  • 893
  • 1
  • 11
  • 25