where or filter on list

C

charles.hebert

Hi,

Can anybody tell me how to to find the nearest value to zero in a list
?

To do that, i'm using list comprenhension :
foo = [-5,-1,2,3] # nearest value to zero ?
[value for value in foo if math.fabs(value) == min([int(math.fabs(x)) for x in foo])]
[-1]

Something simpler ?
How to extend this function to any given value ?

Thanks,

CH.
 
S

skip

foo = [-5,-1,2,3] # nearest value to zero ?
>>>> [value for value in foo if math.fabs(value) == min([int(math.fabs(x)) for x in foo])]
charles> [-1]

charles> Something simpler ?

Well, you can just use the abs() builtin instead of math.fabs. Also, just
compute the min/abs once:

minval = min([int(math.fabs(x)) for x in foo])
[value for value in foo if fabs(value) == minval]

Another way might be to sort by absolute value:

intermed = [(abs(v), v) for v in foo]
intermed.sort()
intermed[0][1]

That only gives you one of possibly many values closest to zero.

charles> How to extend this function to any given value ?

Just subtract that value from all values in the list:

intermed = [(abs(v-x), v) for v in foo]
intermed.sort()
intermed[0][1]

Skip
 
D

Duncan Booth

Another way might be to sort by absolute value:

intermed = [(abs(v), v) for v in foo]
intermed.sort()
intermed[0][1]

It is slightly simpler if you use sorted (assuming a recent enough Python):

intermed = sorted(foo, key=abs)
print intermed[0]

The sorted list is of course the best way if you want to find not just one
value but a group, e.g. the n nearest to 0.

For nearest to a non-zero value v the version with sorted becomes:

intermed = sorted(foo, key=lambda x:abs(x-v))
 
P

Philipp Pagel

Can anybody tell me how to to find the nearest value to zero in a
list?
foo = [-5,-1,2,3] # nearest value to zero ?
[value for value in foo if math.fabs(value) == min([int(math.fabs(x)) for x in foo])]
[-1]

Something simpler ?

Maybe something like this:

mindist = min(map(abs, foo))
filter(lambda x: abs(x) == mindist, a)[0]

Only annoyance: we compute abs twice for each value. We could probably
avoid that by using reduce() and a suitable function...
How to extend this function to any given value ?

By subtracting the desired value from foo.

cu
Philipp
 
L

Larry Bates

Hi,

Can anybody tell me how to to find the nearest value to zero in a list
?

To do that, i'm using list comprenhension :
foo = [-5,-1,2,3] # nearest value to zero ?
[value for value in foo if math.fabs(value) == min([int(math.fabs(x)) for x in foo])]
[-1]

Something simpler ?
How to extend this function to any given value ?

Thanks,

CH.

One of I'm sure many ways:

import sys
def closest(value, list):
m=None
mdistance=sys.maxint
for entry in list:
distance=abs(value-entry)
if distance < mdistance:
m=entry
mdistance=distance
return m

if __name__ == "__main__":
foo = [-5,-1,2,3]
print closest(0, foo)

Note: If you know that the list is ordered you can break out of the
loop you can optimize the loop by breaking out when you start getting
further away from value or you might be able to use the bisect module
to find it faster. If the lists are small it probably isn't worth
the extra effort. If they are large and sorted look at bisect.

Question: what if two values are equidistant?

-Larry bATES
 
S

skip

>> Another way might be to sort by absolute value:
>>
>> intermed = [(abs(v), v) for v in foo]
>> intermed.sort()
>> intermed[0][1]

Duncan> It is slightly simpler if you use sorted (assuming a recent
Duncan> enough Python):

Duncan> intermed = sorted(foo, key=abs)
Duncan> print intermed[0]

Yeah, sorted() is new enough that my brain generally doesn't realize it's
available. I also never remember the key parameter to list.sort(). Now
that you mention it:
>>> foo = [5, 2, -1, -7, 3, -6, 2, 12]
>>> foo.sort(key=abs)
>>> foo
[-1, 2, 2, 3, 5, -6, -7, 12]

(assuming you don't mind reording the list - if you do, then sorted() is
your friend).

Skip
 
N

Neil Cerutti

Hi,

Can anybody tell me how to to find the nearest value to zero in a list
?

To do that, i'm using list comprenhension :
foo = [-5,-1,2,3] # nearest value to zero ?
[value for value in foo if math.fabs(value) == min([int(math.fabs(x)) for x in foo])]
[-1]

Something simpler ?
How to extend this function to any given value ?

A hand-crafted loop seems like an efficient solution:

def closest_to(n, seq):
m = 0
for i in xrange(1, len(seq)):
if abs(n-seq) < abs(n-seq[m]):
m = i
return seq[m]

Putting my faith in Python builtins instead:

def closest_to(n, seq):
s = [abs(n-x) for x in seq]
return seq[s.index(min(s))]
 
D

Duncan Booth

Another way might be to sort by absolute value:

intermed = [(abs(v), v) for v in foo]
intermed.sort()
intermed[0][1]

Duncan> It is slightly simpler if you use sorted (assuming a recent
Duncan> enough Python):

Duncan> intermed = sorted(foo, key=abs)
Duncan> print intermed[0]

Yeah, sorted() is new enough that my brain generally doesn't realize it's
available. I also never remember the key parameter to list.sort().

You're not the only one who has trouble remembering just what is in each
version.
Now that you mention it:
foo = [5, 2, -1, -7, 3, -6, 2, 12]
foo.sort(key=abs)
foo
[-1, 2, 2, 3, 5, -6, -7, 12]

(assuming you don't mind reording the list - if you do, then sorted() is
your friend).

And for Python 2.5 users only we have the exciting new option of:
foo = [5, 2, -1, -7, 3, -6, 2, 12]
min(foo, key=abs)
-1
 
L

Larry Bates

What I mean is: What if there are two items that are
equidistant to what you are searching for?


Example:

foo = [-5,-1,1,3,5]
print closest(0, foo)

-1 and 1 are both "equally close" to zero that I'm
searching for. This is an edge case that you didn't
define an answer to and closest function that I
wrote may (or may not) return the correct answer.

-Larry

Thanks all !
Question: what if two values are equidistant?
... intermed = [(abs(v), v) for v in foo]
... intermed.sort()
... return [x[1] for x in intermed if x[0] == intermed[0][0]]
...
print closest([-20,-10,10,15],0)
[-10, 10]

Works fine !

(now with sorted ... ?)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top