5

I have this:

a = min(max(x, 1), 100)

Is there anything more pythonic?

Michał Perłakowski
  • 70,955
  • 24
  • 137
  • 155
Schultz9999
  • 7,955
  • 6
  • 43
  • 80
  • 6
    That is pretty pythonic – sshashank124 Apr 24 '15 at 22:03
  • 2
    How does that not satisfy you? You can't really hope to get even more compact – Niklas B. Apr 24 '15 at 22:03
  • @sshashank124 well, i'd say this is pathonic but pathetical :) `a = x if 1 < x < 100 else 1 if x < 1 else 100` because it's read as an English sentence. The one in question is not. – Schultz9999 Apr 24 '15 at 22:06
  • definition of pythonic from https://docs.python.org/2/glossary.html: *An idea or piece of code which closely follows the most common idioms of the Python language, rather than implementing code using concepts common to other languages. For example, a common idiom in Python is to loop over all elements of an iterable using a for statement.* The ternary expression, being pretty unique in Python (in terms of its syntax and readability, not in terms of the idea of ternary operator), is pretty Pythonic in my opinion. Max and min are in pretty much every language. – Shashank Apr 24 '15 at 22:39
  • @gothdo http://meta.stackoverflow.com/questions/334693/why-was-an-edit-adding-an-answer-to-a-question-approved –  Sep 16 '16 at 18:46
  • 1
    @Will I read that. I rolled back because the "to editors" note added by OP should rather be a comment. – Michał Perłakowski Sep 16 '16 at 19:23

5 Answers5

5

What about:

a = 1 if x < 1 else 10 if x > 10 else x

It gives the readability that you wanted without the redundancy of the version in your comment. It is verbose because it defines the centre case first and then has to distinguish between the two ends. This way of doing it cuts the ends of first and everything left is in range.

neil
  • 2,797
  • 1
  • 12
  • 11
4

If it's for an array, you could use numpy.clip.

Otherwise, I think your solution is the best one. Or you could define your own function that does the same for a single element, if you do that at multiple places.

Valentin Lorentz
  • 8,859
  • 5
  • 42
  • 63
2

Another option that you might consider more pythonic:

if x > 100:
    x = 100
elif x < 1:
    x = 1
Ella Sharakanski
  • 2,371
  • 2
  • 22
  • 43
  • technically, the question asks to assign this value to `a` -- so this is almost but not quite fulfills that. – gabe Apr 24 '15 at 22:44
  • 1
    You are correct, if assigning to `a` is necessary use `a = x` first and then use my code with `a` instead of `x` – Ella Sharakanski Apr 24 '15 at 22:51
2

What about something a little different:

a = (1, x, 100)[-(x<1)+1+(x>100)]

or if you define your limits as

lo, hi = (1, 100)
a = (lo, x, hi)[-(x<lo)+1+(x>hi)]

Or rearrange your data, and it looks more elegant:

a = (x,lo,hi)[(x<lo)-(x>hi)]

This is possible in python because booleans behave like the values 0 and 1, allowing the math inside the [] to get the right index of the tuple.

chapelo
  • 2,244
  • 11
  • 18
-1
a = x if x in range(1,100) else 1 if x < 1 else 100

Do you really need to floor at 1 and ceil at 100 ?

kguest
  • 3,730
  • 3
  • 28
  • 31
Saloparenator
  • 180
  • 10
  • 1
    This takes a lot of space and `x in range(1, 100)` is not better than `1 < x < 100` – Ella Sharakanski Apr 24 '15 at 22:22
  • but it is really pythonic, it read itself in English, equal X if X in range 1 to 100 – Saloparenator Apr 24 '15 at 22:28
  • Still, a bad approach IMO. Won't work for 1000000000 on my computer. And `1 < x < 100` reads just as well – Ella Sharakanski Apr 24 '15 at 22:31
  • @Saloparenator this generates a list (in Py2) of all the ints between 1 and 100, and then iterates through them to see if x is one of them. The complexity goes through the roof compared to a constant time comparison! – ThinkChaos Apr 24 '15 at 22:45
  • 1
    @Ella Shar You have a good approach btw. And you are right that it will not work for **put huge number here**. – Saloparenator Apr 24 '15 at 22:46
  • @ThinkChaos you are right it generate all number. – Saloparenator Apr 24 '15 at 22:50
  • Note that if x is 1.1 (or any other decimal), your equation sets it to 100... that's problematic – Foon Apr 24 '15 at 23:11
  • 1
    Actually, having just read this question [http://stackoverflow.com/questions/30081275/why-is-1000000000000000-in-range1000000000000001-so-fast], in Python 3 this will be fast as the range is never generated - it will in fact check the bounds of the range. – neil May 06 '15 at 15:56