Halter
Halter

Reputation: 48

How to find the two indexes from a list whos values are closest to zero

I'm working on a piece for my GA (fitness calculation actually) and I need to get the indexes of two values from a list whos values are closest to zero. I have been looking for about an hour all over the internet and though it seems I have become extremely close, and it looks like it should work, testing with print statements show that my code isnt working..

My process right now is:

  1. Find the closest index and store it
  2. Delete it from original array
  3. Find the new closest

this is the code in question:

closest = min(range(len(fitness_levels)), key=lambda i: abs(fitness_levels[i]-0))
fitness_levels.pop(closest)
second_closest = min(range(len(fitness_levels)), key=lambda i: abs(fitness_levels[i]-0))

when fitness_levels = [-20, 23, -55, 11, 10, -18, -48, 16, -60, 20, 22, 16, 21, 66, 10, 46, -42] granted those numbers are generated completely at random.

Like I said, when i do some checking with print statements i find this method doensnt work in multiple ways, at one point i even ended up with the same index different values. Does anyone have a better workable way to do this? - python 2.7.x

Side note- i come from a php background, still warming up to python, so some syntax could be wrong...

Upvotes: 0

Views: 806

Answers (4)

Developer
Developer

Reputation: 8400

How about:

>>> from numpy import argsort,abs
>>> fitness_levels = [-20,23,-55,11,10,-18,-48,16,-60,20,22,16,21,66,10,46,-42]
>>> i,j = argsort(abs(fitness_levels))[:2]
>>> print (i,fitness_levels[i]),(j,fitness_levels[j])
>>> (14 10) (4 10)

Upvotes: 0

inspectorG4dget
inspectorG4dget

Reputation: 113905

While sorting with an abs key would work, that's an nlogn solution. Here's a linear solution

fitness_levels = [-20, 23, -55, 11, 10, -18, -48, 16, -60, 20, 22, 16, 21, 66, 10, 46, -42]
a,b = sorted(fitness_levels[:2], key=abs) # setting defaults. a<=b
ia, ib = 0,1 # indices
for i,val in enumerate(fitness_levels[2:]): # use itertools.islice for large lists (for constant space)
  if abs(val) < abs(a):
    b,a = a,val
    ib, ia = ia, i
  elif abs(val) < abs(b):
    b = val
    ib = i

Upvotes: 3

Ashwini Chaudhary
Ashwini Chaudhary

Reputation: 250881

Something like this:

>>> lis = [-20, 23, -55, 11, 10, -18, -48, 16, -60, 20, 22, 16, 21, 66, 10, 46, -42]
for i,x in enumerate(sorted(enumerate(lis), key=lambda x:abs(0 - x[1]))[:2]):
    x = list(x)
    x[0] -= i    #reduce index as an item was removed from the list
    ind, val = x
    print "{}->{}".format(ind, val)
...     
4->10
13->10

If you don't want index to be decreased then simply this is enough:

>>> sorted(enumerate(lis), key=lambda x:abs(0-x[1]))[:2]
[(4, 10), (14, 10)]

Upvotes: 0

Jon Clements
Jon Clements

Reputation: 142106

I'd go for:

fitness_levels = [-20, 23, -55, 11, 10, -18, -48, 16, -60, 20, 22, 16, 21, 66, 10, 46, -42]

import heapq
closest2 = heapq.nsmallest(2, ((abs(val), idx) for idx, val in enumerate(fitness_levels)))
# [(10, 4), (10, 14)]
indices = [el[1] for el in closest2]
# [4, 14]

Upvotes: 0

Related Questions