Smart way to remove item from array (values only)

13 views
Skip to first unread message

Jochen Daum

unread,
Apr 16, 2008, 5:37:13 PM4/16/08
to ph...@phpug.org.nz
Hi,

is there a smart way to remove an entry from an array of value without looping through it?

I found array_splice, but I would need to loop for the offset I guess?

Regards,

Jochen

Cameron Junge

unread,
Apr 16, 2008, 5:53:33 PM4/16/08
to nzp...@googlegroups.com

Array_search?

 

$loc = array_search($array, $value);

If ($loc != -1) {

            unset($array[$loc]);

}

 


Mike Cochrane

unread,
Apr 16, 2008, 5:57:52 PM4/16/08
to nzp...@googlegroups.com
You can just unset() it if you can identify it by it's key.

eg:

$myarray = array(1 => 'tree', 2 => 'fish', 3 => 'horse');
unset($myarray[2]);
print_r($myarray);

Outputs:

Array
(
[1] => tree
[3] => horse
)


Alternatively you can search for the value if they are unique and then
unset:

$key = array_search('horse', $myarray);
if ($key !== false) {
unset($myarray[$key]);
}
print_r($myarray);

Outputs:

Array
(
[1] => tree
)


HTH
- Mike


--
Mike Cochrane
Web Team Leader

gardyneHOLT - design partners
18 Beresford Square Newton
PO Box 3340 Auckland New Zealand
p +64 9 300 3155 f +64 9 302 3349 m 021 545 565
skype gardyneholt_mikec
www.gardyneholt.co.nz

Mike Cochrane

unread,
Apr 16, 2008, 6:00:23 PM4/16/08
to nzp...@googlegroups.com
Close, but array_search returns Boolean FALSE on not found so you need
to check for that explicitly.
if ($loc !== false)

- Mike :-)

Cameron Junge wrote:
>
> Array_search?
>
> $loc = array_search($array, $value);
>
> If ($loc != -1) {
>
> unset($array[$loc]);
>
> }
>

> ------------------------------------------------------------------------
>
> *From:* nzp...@googlegroups.com [mailto:nzp...@googlegroups.com] *On
> Behalf Of *Jochen Daum
> *Sent:* Thursday, 17 April 2008 9:37 a.m.
> *To:* ph...@phpug.org.nz
> *Subject:* [phpug] Smart way to remove item from array (values only)


>
> Hi,
>
> is there a smart way to remove an entry from an array of value without
> looping through it?
>
> I found array_splice, but I would need to loop for the offset I guess?
>
> Regards,
>
> Jochen
>

Aaron Cooper

unread,
Apr 16, 2008, 6:01:50 PM4/16/08
to nzp...@googlegroups.com
Heh, was trying to work this very thing out the other day. Here's a simplificatoin of what I ended up with using one line:
 
 
$array = array('firstname'=>'aaron','surname'=>'cooper','location'=>'albany');
  
// Remove 'cooper' from the array
$new_array = explode(',',str_replace('cooper,','',(join(',',$array))));
  
print_r($new_array);   // Array ([0]=>aaron [1]=>albany)
 
 
Cheers
Aaron

Tim Oliver

unread,
Apr 16, 2008, 6:46:47 PM4/16/08
to nzp...@googlegroups.com
Aaron Cooper wrote:
> Heh, was trying to work this very thing out the other day. Here's a
> simplificatoin of what I ended up with using one line:
>
>
> $array =
> array('firstname'=>'aaron','surname'=>'cooper','location'=>'albany');
>
> // Remove 'cooper' from the array
> $new_array = explode(',',str_replace('cooper,','',(join(',',$array))));
>
> print_r($new_array); // Array ([0]=>aaron [1]=>albany)

Heh, hope you don't have any fields with commas in them, or that surname
isn't the last column... is there some reason to avoid just

foreach($array as $key => $val) {
if($val == 'whatever') unset($array[$key]);
}

?

--
Tim Oliver
t...@e2-media.co.nz

Jochen Daum

unread,
Apr 16, 2008, 6:49:22 PM4/16/08
to ph...@phpug.org.nz

Hi,

yeah, you need to identify the things you are searching for by key. I was looking for a way with numbered key, i.e. with values (and implicit keys). No biggie, keys are fine.

Thanks everyone,

Jochen

Cameron Junge

unread,
Apr 16, 2008, 6:53:22 PM4/16/08
to nzp...@googlegroups.com

Another way would be array_filter

 

$array = array_filter($array, create_function(‘$v’, ‘return $v !=’.$value.’;));

 

I keep forgetting about the array functions.

 

Cam

 


From: nzp...@googlegroups.com [mailto:nzp...@googlegroups.com] On Behalf Of Jochen Daum
Sent: Thursday, 17 April 2008 10:49 a.m.
To: ph...@phpug.org.nz
Subject: [phpug] Smart way to remove item from array (values only)

 


Hi,

Cameron Junge

unread,
Apr 16, 2008, 6:56:42 PM4/16/08
to nzp...@googlegroups.com

Oops, forgot the last single quote:

 

$array = array_filter($array, create_function(‘$v’, ‘return $v !=’.$value.’;’));

 

From: nzp...@googlegroups.com [mailto:nzp...@googlegroups.com] On Behalf Of Cameron Junge
Sent: Thursday, 17 April 2008 10:53 a.m.
To: nzp...@googlegroups.com
Subject: [phpug] Re: Smart way to remove item from array (values only)

Aaron Cooper

unread,
Apr 16, 2008, 7:09:57 PM4/16/08
to nzp...@googlegroups.com
Yeah I know keys are lost in the process, and as Tim eloquently pointed out, if the field has a comma in it, it would fail.
 
But validity of the data was not part of the question. That code was fine for me as validation had already occured, and the array wasn't associative to begin with. This was just an illustration.
 
True about the problem with the last element though. I will need to check my code for issues with that one. For me, the submit button value on a form is always last, so should be fine.
 
I found the site where I got this method. With 5 other methods and speed benchmarks (this method was the fastest): http://lixlpixel.org/php-benchmarks/remove-array-items-by-value/

Steve Wake

unread,
Apr 17, 2008, 7:07:11 AM4/17/08
to nzp...@googlegroups.com
When you get a result set off a database query, e.g MYSQL_BOTH, you can get both a numeric and a named array as a result, e.g. 

row[0]
row['ID']

are the same thing; lovely.

How do you do this in your own code? 

It's been bugging me for a long time.

Sid Bachtiar

unread,
Apr 17, 2008, 3:14:15 PM4/17/08
to nzp...@googlegroups.com
You should use MYSQL_ASSOC if you don't want the numeric index in the
first place.

But to clear it, just check using is_numeric, and discard/ignore the
numerical index.

Jochen Daum

unread,
Apr 17, 2008, 3:08:32 PM4/17/08
to PHPUG

Haven't tried but $arr = array_merge($arr, array_values($arr)); ???

Regards,

Jochen

What is smart about smartgates and their website?

automatem .
software solutions
EMAIL
WEB
PHONE
MOBILE
J...@AUTOMATEM.CO.NZ
WWW.AUTOMATEM.CO.NZ
0800 GO 4 AUTO (0800 464288)
021 567 853


On Thu, Apr 17, 2008 at 11:07 PM, Steve Wake <stephe...@gmail.com> wrote:

Mike Cochrane

unread,
Apr 17, 2008, 7:19:33 PM4/17/08
to nzp...@googlegroups.com
Hi Aaron,

Aaron Cooper wrote:
> I found the site where I got this method. With 5 other methods and
> speed benchmarks (this method was the fastest):
> http://lixlpixel.org/php-benchmarks/remove-array-items-by-value/

I just had a look at the results on there and they didn't make sense so
I had to rerun them. I created this:
http://dev.gardyneholt.co.nz/benchmark1.phps
to test them and included that way I would have done it - test5 near the
bottom. I included the 4 tests that have sufficient code to just copy
and paste and test. One of them, "fast for loop", doesn't actually work.
I haven't taken any time to look at these functions or interpret the
results, I'll leave that up to you guys.

Results from running it here:
http://dev.gardyneholt.co.nz/benchmark1.php
array_search in a while loop is fastest in my tests.

Feel free to take the code and test on your one systems. I'd be
interested to know if someone's getting wildly different results.

- Mike

Aaron Cooper

unread,
Apr 17, 2008, 7:38:34 PM4/17/08
to nzp...@googlegroups.com
Interesting Mike cheers.

My results are pretty much the same, except Foreach and Explode/Join swap
positions every now and then (More often than not, Explode/Join leads), as
too do the Fast for loop and For loop. But those pairs never swap positions
with the other. The for loops are quite a bit slower.

Surprised at the huge difference the while/array search wins by. Going a bit
off topic now though. I'm sure there is a very good reason why Jochen didn't
want a loop.

Cheers
Aaron

Cameron Junge

unread,
Apr 17, 2008, 7:47:54 PM4/17/08
to nzp...@googlegroups.com
I hate to point out the obvious...

While-search is approx. 50% faster than the for-loop test (ignoring the
non-working fast-for-loop). That's over 500 iterations.

So:

22.24588ms / 500 => 0.0444918ms or approx. 4.4us per iteration.
47.30511ms / 500 => 0.0946102ms or approx. 9.5us per iteration.

The difference is 5.1us. No idea of the error deviation in that result.

No one is going to notice the difference, and who the hell is going to
run a loop over enough items to make that difference noticeable. Even
the difference between 47 & 22 milliseconds isn't going to be
noticeable.

I myself have done some optimizations on code for stuff like this. But,
it's pointless really. Focus on the bigger gains, not the little tiny
ones. Remove most of the bigger bottlenecks & you'll notice the
difference. Remove ones like the above and you'll hardly notice them.

"Premature optimization is the root of all evil." - Donald Knuth.

-----Original Message-----
From: nzp...@googlegroups.com [mailto:nzp...@googlegroups.com] On
Behalf Of Mike Cochrane
Sent: Friday, 18 April 2008 11:20 a.m.
To: nzp...@googlegroups.com

Aaron Cooper

unread,
Apr 17, 2008, 8:02:18 PM4/17/08
to nzp...@googlegroups.com
True,

But if someone wants to spend the time testing it based on interest, and
comes up with a clear winning method, does it not help everyone for future
knowledge, regardless of how small a difference it makes?

I mean, most of those methods are similar in the amount of time they take to
type. (bugger all). So if one displays a clear advantage (note I say clear,
not huge), it makes sense to take it into account to me.

Code readability will be the next topic to come up I would say.

So yeah, it is obvious. I think we all spotted the miniscule timings. That
still doesn't detract from the fact that I understand just a little bit more
about the language now.

Again, this topic has way OT now. Jochen never mentioned that his reason for
not using loops was perfomance.

Aaron


----- Original Message -----
From: "Cameron Junge" <cju...@author-it.com>
To: <nzp...@googlegroups.com>

Mike Cochrane

unread,
Apr 17, 2008, 8:06:59 PM4/17/08
to nzp...@googlegroups.com
Well put :-) For most normal use cases a gain like this is pointless to
go for.

I was just surprised to see someone claim that it was faster to convert
an array to a string, perform string operations and then go back to an
array again - but they were in fact correct in claiming that. And I had
a friend (another nzphpug reader) that pointed out that my solution was
missing from the benchmark so had to compare it.

I do have real cases where there are sometimes 50K+ iterations and so
small gains like this are useful. Although I can't remember ever needing
to remove an array item by value before in real code, that occurs as a
bad thing when I'm conceptualising code - but at least I know how to do
it fast now.

- Mike :-)

Cameron Junge wrote:
> I hate to point out the obvious...
>
> While-search is approx. 50% faster than the for-loop test (ignoring the
> non-working fast-for-loop). That's over 500 iterations.
>
> So:
>
> 22.24588ms / 500 => 0.0444918ms or approx. 4.4us per iteration.
> 47.30511ms / 500 => 0.0946102ms or approx. 9.5us per iteration.
>
> The difference is 5.1us. No idea of the error deviation in that result.
>
> No one is going to notice the difference, and who the hell is going to
> run a loop over enough items to make that difference noticeable. Even

> the difference between 47& 22 milliseconds isn't going to be


> noticeable.
>
> I myself have done some optimizations on code for stuff like this. But,
> it's pointless really. Focus on the bigger gains, not the little tiny

> ones. Remove most of the bigger bottlenecks& you'll notice the

Cameron Junge

unread,
Apr 17, 2008, 8:13:12 PM4/17/08
to nzp...@googlegroups.com
Oh, and another variable to throw into the mix that hasn't been
mentioned yet: PHP's garbage collector, which runs at random times.

You make valid points... I guess if one was to use as standard a method
that is possibly fractionally faster than another, then that gain
doesn't cost anything (unless it's horribly unreadable/unmaintainable).

Example: I tend to use while(list($key,$value) = each($array)){} instead
of a for loop. It's fractionally faster than a for, and has the
advantage of using less memory (it uses references and a pointer)
[granted, PHP5 allows an array item to be referenced]. I also find it a
bit easier to understand. So a free win, possibly.

Oh, something just jumped into my mind about that while-array_search. Be
careful of an index casting to false (eg: 0). In fact, the method would
fail if the first item was the search item & it had an index of 0.

So the code should be:

function test5($workdata, $item2remove) {
while($key = array_search($item2remove, $workdata) && $key !==
false) {
unset($workdata[$key]);
}
return $workdata;
}

(might be a bit slower with the added comparison...)

Cameron

Dmitry Ruban

unread,
Apr 17, 2008, 8:45:38 PM4/17/08
to nzp...@googlegroups.com
In fact, the test provided is not really accurate. array_search + unset
requires two internal walks through array (you have to find an element
twice) and in this particular case "c" is almost at the beginning of
array. If you try to remove letter "z" you would get different results
where Explode/Join approach wins. In case with "a" letter is the
opposite situation.
No doubt strings operations are faster then arrays operations.

Aaron Cooper:

Steve Wake

unread,
Apr 17, 2008, 8:52:29 PM4/17/08
to nzp...@googlegroups.com
Sorry, wasn't very clear, but I'd like an array which can be indexed both numerically and by key.

For example this dies with an 'undefined offset 0', however this would work if the array was instead a result set returned with MYSQL_BOTH specified on fetch.

$a = array ("One" => "First", "Two" => "Second", "Three" => "Third");
print_r($a[0]);

Can we get the same functionality in our own code as from the MYSQL_BOTH of a mysql fetch? Am I missing something really obvious here?

Mike Cochrane

unread,
Apr 17, 2008, 9:34:05 PM4/17/08
to nzp...@googlegroups.com
Dmitry Ruban wrote:
>
> In fact, the test provided is not really accurate. array_search +
> unset requires two internal walks through array (you have to find an
> element twice) and in this particular case "c" is almost at the
> beginning of array. If you try to remove letter "z" you would get
> different results where Explode/Join approach wins. In case with "a"
> letter is the opposite situation.
If you try remove 'z' then Explode/Join fails as it's looking for 'z,'
but that doesn't exist.

- Mike :-)

Mike Cochrane

unread,
Apr 17, 2008, 9:37:21 PM4/17/08
to nzp...@googlegroups.com
Thanks for the correction, I noticed that as I was heading out to lunch.

Also the Explode/Join example doesn't match the last item in the array
and needs a couple more string operations to handle that case and it
fails if the value to remove is the suffix of another value.
eg removing 't' from: array('test', 't') would give array('tes');
So Explode/Join should be used very carefully.

This includes fixes for not matching the first item with 'while
array_search' and not matching the last with 'Explode/join'.
http://dev.gardyneholt.co.nz/benchmark2.php
http://dev.gardyneholt.co.nz/benchmark2.phps

- Mike

Cameron Junge wrote:
> Oh, and another variable to throw into the mix that hasn't been
> mentioned yet: PHP's garbage collector, which runs at random times.
>
> You make valid points... I guess if one was to use as standard a method
> that is possibly fractionally faster than another, then that gain
> doesn't cost anything (unless it's horribly unreadable/unmaintainable).
>
> Example: I tend to use while(list($key,$value) = each($array)){} instead
> of a for loop. It's fractionally faster than a for, and has the
> advantage of using less memory (it uses references and a pointer)
> [granted, PHP5 allows an array item to be referenced]. I also find it a
> bit easier to understand. So a free win, possibly.
>
> Oh, something just jumped into my mind about that while-array_search. Be
> careful of an index casting to false (eg: 0). In fact, the method would

> fail if the first item was the search item& it had an index of 0.


>
> So the code should be:
>
> function test5($workdata, $item2remove) {

> while($key = array_search($item2remove, $workdata)&& $key !==

> the difference between 47& 22 milliseconds isn't going to be


> noticeable.
>
> I myself have done some optimizations on code for stuff like this. But,
> it's pointless really. Focus on the bigger gains, not the little tiny

> ones. Remove most of the bigger bottlenecks& you'll notice the

Dmitry Ruban

unread,
Apr 17, 2008, 10:38:43 PM4/17/08
to nzp...@googlegroups.com
The point was that the speed of array functions depends on the position
of an item. whereas join/explode speed does not depend on it :)


Mike Cochrane:

Tim Oliver

unread,
Apr 17, 2008, 10:57:54 PM4/17/08
to nzp...@googlegroups.com
Dmitry Ruban wrote:
>
> The point was that the speed of array functions depends on the position
> of an item. whereas join/explode speed does not depend on it :)

But it also fails on way more edge cases...

I've been fiddling with that testcase, and it's interesting doing things
like moving the char to remove to 'z', and then working on

$workdata = array_fill(0,100,'z');

(which breaks two of the testcases!)

I get pretty random results, and I note that some of the algorithms are
modifying the copy of the array in the function scope, and some are
making a new array of everything else - I don't think any of these
results are statistically worth drawing conclusions on. We're also not
considering memory usage, for all these cases where we're building new
arrays rather than modifying the existing one.

This is how I'd prioritise things when considering algorithm choices:

* works for all inputs (having to put '//doesn't work on the last
element in the string' it *way* more important than microsecond efficiency)
* is immediately understandable and clear when reading the code (no
magic tricks)
* efficiency

--
Tim Oliver
t...@e2-media.co.nz

Jochen Daum

unread,
Apr 17, 2008, 11:43:01 PM4/17/08
to nzp...@googlegroups.com
Hi,

I was really looking for a neat way (read: easy to understand code) to find all parents in a parent-child relationship (possibly chained) that have no parent themselves. Its not in a database, its a form, so no performance issue.

anyway, it is an interesting discussion, hope noone is offended by off topic.

Going through the tests on that website would be a great PHPUG Auckland speaking topic. Anyone?


Regards,

Jochen

What is smart about smartgates and their website?

automatem .
software solutions
EMAIL
WEB
PHONE
MOBILE
J...@AUTOMATEM.CO.NZ
WWW.AUTOMATEM.CO.NZ
0800 GO 4 AUTO (0800 464288)
021 567 853


Jochen Daum

unread,
Apr 17, 2008, 11:44:02 PM4/17/08
to nzp...@googlegroups.com
Hi,

have you tried my suggestion? The order would be wrong, but that may not matter?

Jochen

Jochen Daum

unread,
Apr 17, 2008, 11:44:02 PM4/17/08
to nzp...@googlegroups.com
Hi,

have you tried my suggestion? The order would be wrong, but that may not matter?

Jochen
Reply all
Reply to author
Forward
0 new messages