0

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

6
  • How do these range work? Why the go from 1-10 to 12-16 and then 18-29? Commented Dec 2, 2021 at 19:27
  • No but python 3.10 is adding match statements for case-like structures. Commented 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. Commented Dec 2, 2021 at 19:29
  • First of all you can make these elif statements to make your program run possibly faster Commented 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. Commented Dec 2, 2021 at 19:31

5 Answers 5

4

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)
Sign up to request clarification or add additional context in comments.

4 Comments

level is assigned to the first element of the next range, not the range where it was found.
Well spotted, thanks. This should correct it.
Also, is that else supposed to be attached to the if, or to the for?
The for, but they're functionally equivalent. I've corrected it anyway.
3

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

1

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

0

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

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.