def get_pos(rel_dates):
"""returns the positions of the dates closest to 25%, 50%, and 75%"""
pos = [0] # first element
dates25, dates50, dates75 = [], [], []
for date in rel_dates:
dates25.append(abs(date-25))
dates50.append(abs(date-50))
dates75.append(abs(date-75))
pos.append(dates25.index(min(dates25)))
pos.append(dates50.index(min(dates50)))
pos.append(dates75.index(min(dates75)))
pos.append(len(rel_dates)-1) #last element
return pos
Refactorings
No refactoring yet !
Kevin Baribeau
January 30, 2010, January 30, 2010 20:39, permalink
You may or may not like this.
Instead of building pos with append, I build the whole thing in one line. I also used list comprehensions to build the dates.
I think both changes are more declarative, but probably less newbie friendly.
def get_pos(rel_dates): """returns the positions of the dates closest to 25%, 50%, and 75%""" dates25 = [abs(date-25) for date in rel_dates] dates50 = [abs(date-50) for date in rel_dates] dates75 = [abs(date-75) for date in rel_dates] return [ 0, dates25.index(min(dates25)), dates50.index(min(dates50)), dates75.index(min(dates75)), len(rel_dates)-1 ]
Ants
January 31, 2010, January 31, 2010 07:01, permalink
It looks a bit frightening that both implementations above use O(3 * N) space for the 3 new arrays created, and at best O(3 * N) complexity to determine the minimum value from each of those new arrays.
bob
February 14, 2010, February 14, 2010 18:58, permalink
Since the array is sorted, you should use binary search. Look at the "bisect" module and the bisect.bisect() family of functions.
onk
March 7, 2010, March 07, 2010 21:07, permalink
@bob's bisect.
from bisect import bisect
def pos(ls, x):
pos = bisect(ls, x)
if ls[pos] - x > x - ls[pos - 1]:
return pos - 1
else:
return pos
def spots(rel_dates):
"""Returns the positions of the dates closest to 25%, 50%, and 75%"""
return [pos(rel_dates, x) for x in [25, 50, 75]]
Colin Wallace
April 13, 2010, April 13, 2010 22:43, permalink
I simply re-wrote redundant parts of the code. It's shorter, and more memory-efficient, but probably not any faster.
def get_pos(rel_dates):
"""returns the positions of the dates closest to 25%, 50%, and 75%"""
ret = [0]
for sub in xrange(25, 100, 25):
dates = [abs(date-sub) for date in rel_dates]
ret.append(dates.index(min(dates)))
ret.append(len(rel_dates)-1)
return ret
The function takes an list of floats ranging from 0.0 to 100.0 in an ascending order. It returns a list of indexes with the indexes of the elements closest to 25.0, 50.0 and 75.0.
The intention is to label a time axis, where the labels should correspond to their relative position.