Delete element from within an array

I have tried looking and cannot find it.

If I have an array like this

tt=array(10,2,23,14)

How do I eliminate the number 23 from the array.

What I mean specifically is to delete the element within the array … totally… not leave it blank or null.

If you know that the value is the third one in the array:

$tt = array(10, 2, 23, 14);

unset($tt[2]);

If you want to remove every element with the value 23:

$tt = array(10, 2, 23, 14);

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

That loop might be a bit inefficient/slow – the unset can also cause set fragmentation slowing later iterations. This actually sucks a bit more RAM while running, but releases itself quickly enough:


$tt = array(10, 2, 23, 14);
$tt=array_diff($tt,array('23'));

Since array_diff returns all elements in the first array that don’t match elements in the second array.

Another approach would be to use array_search to find the matching key instead of iterating it.


if ($key=array_search('23',$tt)) unset($tt[$key]);

Assuming there’s only one. to check for multiple instances, I’d just use “while” instead of “if”.

An approach using array_filter may also be worth looking at.

Or just… not putting the 23 in the array in the first place… what input are you getting, and why do you need to remove one?

Do the keys have to retain their original values or not?

Today’s entry of the PHP thread of the day series is relevant to this question.

No!

First, this won’t work - $value isn’t bound to the source value array (To do this use “foreach ($array as $key => &$value)” and note the ampersand which causes the value to be passed by reference). Second, if you did receive the $value by reference, deleting a value on an object or array under iteration can cause undefined behavior by PHP.

LOOK CLOSER. He’s calling $tt (the parent) by key for the unset, NOT $value. As such you don’t have to pull $value by reference! Not sure where you were going with that, but… no, you’re WAY off the money there.

unset inside foreach works just fine. First, foreach does the same thing as an array_walk, which is a pointer based operation using internal pointers… so the pointer to ‘next’ should still be valid even with the unset…

Which is why his code runs just FINE!

Oh, and array_filter and it’s kine are problematic since you can’t pass values to the user function and frankly heavy on the overhead (with the nested userland function call) is the slowest of them too… after mentioning it above I gave it a whirl, NOT worth the effort.

Should and is aren’t always the same with PHP and you should know that by now.

From the docs of [fphp]array_walk[/fphp]

I’ve seen PHP do bizarre things if you unset an element - particularly the element that will be next - in a foreach. Now granted, this behavior may have be fixed, but I long ago made it a point to avoid calling unset on the object I’m iterating on (I still do it when I absolutely need to, but that code gets extra heavy testing as a result).

It was slice I was looking for. It was just confusing because there are about thirty array functions.

No, there’s about 80 (or there was about 3 years ago when I counted them all).

And don’t you just love that most array functions have arguments in the order (needle, haystack) and most string functions work in (haystack, needle) order?? heh heh - Love PHP, but I don’t love it’s inconsistencies.

foreach is different, though:

Since the foreach is looping through a copy of the array, changing the original array will not alter the array which is being looped through, and thus, no conflict should occur.

In other words, this:

$array = array(1, 2, 1, 4, 1, 6, 1, 8, 1, 10);

$needle = 1;

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

should be functionally identical to this:

$array = array(1, 2, 1, 4, 1, 6, 1, 8, 1, 10);

$needle = 1;

for($i = 0, $array_copy = $array, $length = count($array_copy); $i < $length; $i++) {
 if($array_copy[$i] == $needle) {
  unset($array[$i]);
 }
}

but not this:

$array = array(1, 2, 1, 4, 1, 6, 1, 8, 1, 10);

$needle = 1;

for($i = 0, $length = count($array); $i < $length; $i++) {
 if($array[$i] == $needle) {
  unset($array[$i]);
 }
}

At least they’re consistent within those two, completely unrelated, groups of functions. I never understood how folks get hung up on this particular setup; maybe we shouldn’t have used the term “needle” and “haystack” for both groups.

No, it isn’t consistent. [fphp]str_replace[/fphp] and [fphp]str_ireplace[/fphp] is (needle, replace, haystack)

I still feel the defining feature of PHP 6 should be shunting all existing functions to a legacy namespace. With a php.ini setting enabled the legacy namespace is imported to the root namespace. Otherwise the whole function library should be redone in an object oriented manner. All arrays would be array objects with the array methods tied to them, same with strings. This would be an enormous change and unlikely to ever occur, but it would be the perfect time to address these problems while using the ini flag to maintain BC.

Fine, mostly consistent. Way to pick on the minor things.

That does rank amongst my pet peeves about PHP – namespace and parameter orders. It literally feels like they just rolled a D6 on the order of parameters in functions… maybe it’s the machine language/assembly coder in me, but come on… pick one, AT&T (dest, value) or Intel (target, value)… don’t mix and match willy-nilly.

But it’s like function, class and method names… camelcase, don’t camelcase, underscores, don’t underscore… PICK ONE!

This is only partly an excuse, but PHP does have coding standards for naming. The other side of the coin is that much of PHP is based on the names of the C functions being called behind-the-scenes.