i got this code, and need to find a more readable and functional way to write it, this project use python 3.6
level_buy = 62
level=0
a1= range(1,10)
a2= range(12,16)
a3= range(18,29)
a4= range(34,46)
a5= range(54,63)
a6= range(73,85)
b1= range(10,12)
b2= range(16,18)
b3= range(29,34)
b4= range(46,54)
b5= range(63,73)
if recomendation=='buy':
if level_buy in a1:
level=a2[0]
if level_buy in b1:
level=b2[0]
if level_buy in a2:
level=a3[0]
if level_buy in b2:
level=b3[0]
if level_buy in a3:
level=a4[0]
if level_buy in b3:
level=b4[0]
if level_buy in a4:
level=a5[0]
if level_buy in b4:
level=b5[0]
if level_buy in a5:
level=a6[0]
if level_buy in b5:
level=85
if level_buy in a6:
level=85
This should return if level_buy is in one of that defined ranges, set level = first number in the next range. Example: level_buy=62, if i call level, should be return 73
Thanks in advance
-
How do these range work? Why the go from 1-10 to 12-16 and then 18-29?Yoshikage Kira– Yoshikage Kira2021年12月02日 19:27:05 +00:00Commented Dec 2, 2021 at 19:27
-
No but python 3.10 is adding match statements for case-like structures.eagle33322– eagle333222021年12月02日 19:28:19 +00:00Commented Dec 2, 2021 at 19:28
-
Looks pretty readable to me. What' s wrong w/it? Maybe put it in a function if you want it to look prettier.Chris– Chris2021年12月02日 19:29:14 +00:00Commented Dec 2, 2021 at 19:29
-
First of all you can make these elif statements to make your program run possibly fasterCozyCode– CozyCode2021年12月02日 19:29:30 +00:00Commented Dec 2, 2021 at 19:29
-
@eagle33322 don't see how that would be any more readable, and I'm not sure this is a good use-case for pattern matching anyway.juanpa.arrivillaga– juanpa.arrivillaga2021年12月02日 19:31:50 +00:00Commented Dec 2, 2021 at 19:31
5 Answers 5
I believe you could replace your series of if statements with a for loop to iterate over your ranges.
ranges = (a1, b1, a2, b2, a3, b3, a4, b4, a5, b5)
if recomendation == 'buy':
for i, ab in enumerate(ranges[:-1]):
if level_buy in ab:
level = ranges[i+1][0]
break
else:
level=85
print(level)
4 Comments
else supposed to be attached to the if, or to the for?for, but they're functionally equivalent. I've corrected it anyway.You could keep the ranges in a list instead of having many separate variables:
ranges = [
range(1,10),
range(12,16),
range(18,29),
...
]
And then you can iterate over the list:
for pos, r in enumerate(ranges):
if level_buy in r:
level = ranges[pos+1][0]
If you don't want the last a range to chain into the first b range, you could perhaps keep two lists.
Comments
Assumptions: that none of the ranges overlap, and that the level is always the upper limit of the next consecutive range. The approach is filtering out the lower levels, and then skipping one to get the correct number.
level_buy = 62
thresholds = [1,10,12,16,18,29,34,46,54,63,73,85]
selection = [t for t in thresholds if level_buy < t]
level = selection[1] if len(selection) > 1 else 85
Comments
You missed declaring recommendation. But here's an alternative to your script if you want to keep a similar logic as the one you posted:
from itertools import chain
recommendation = "buy"
level_buy = 62
level = 0
a1 = range(1, 10)
a2 = range(12, 16)
a3 = range(18, 29)
a4 = range(34, 46)
a5 = range(54, 63)
a6 = range(73, 85)
b1 = range(10, 12)
b2 = range(16, 18)
b3 = range(29, 34)
b4 = range(46, 54)
b5 = range(63, 73)
a_ranges = [a1, a2, a3, a4, a5, a6]
b_ranges = [b1, b2, b3, b4, b5]
combined_ranges = chain.from_iterable(zip(a_ranges, b_ranges))
if recommendation == "buy":
for range_ in combined_ranges:
if level_buy in range_:
level = range_[0]
break
print(level)
Comments
If you are calling this many times, and both don't have too many ranges to set and are willing to have up-front cost and memory required for the lookup table you can pre-process this:
from itertools import chain
level_sets = [(range(1,10), 12),
(range(12,16), 18),
(range(18,29), 34),
(range(34,46), 54),
(range(54,63), 73),
(range(73,85), 85),
(range(10,12), 16),
(range(16,18), 29),
(range(29,34), 46),
(range(46,54), 63),
(range(63,73), 85)]
levels = {l: s for l, s in chain(*([(k, v) for k in r] for r, v in level_sets))}
...
for buy in recommendation_list:
level = levels.get(level_buy)
This basically says for each integer you have some level it will point to. The benefit of doing it this way is that each time you need to get the level for a level buy it's an O(1) operation - so if you had a large number of recommendations to make, it will have a little upfront cost (building the lookup table) and then very little incremental cost (looking up a level buy). This is in contrast with no upfront cost and a O(n) cost each time where n is the number of ranges you have.