Reputation: 48
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:
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
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
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
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
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