Python if-else code style for reduced code for rounding floats2019 Community Moderator ElectionIs floating point math broken?How do I parse a string to a float or int in Python?Printing increments of 0.1 in c#How can I force division to be floating point? Division keeps rounding down to 0?Double increments in JavaPut integers from stdin in listSelecting lines of a file specified by a list of stringsPerfect ROC curve but imperfect prediction accuracyFor loop break doesn't work PythonHow to classify observations based on their covariates in dataframe and numpy?Parse dataframe with specific column and write to sheets in one excel file
Why does Bach not break the rules here?
Stiffness of a cantilever beam
Is a party consisting of only a bard, a cleric, and a warlock functional long-term?
Happy pi day, everyone!
How can I track script which gives me "command not found" right after the login?
Professor being mistaken for a grad student
Hacking a Safe Lock after 3 tries
how to write formula in word in latex
Most cost effective thermostat setting: consistent temperature vs. lowest temperature possible
Why doesn't the EU now just force the UK to choose between referendum and no-deal?
How could a scammer know the apps on my phone / iTunes account?
Employee lack of ownership
Why do Australian milk farmers need to protest supermarkets' milk price?
Why do passenger jet manufacturers design their planes with stall prevention systems?
Is it normal that my co-workers at a fitness company criticize my food choices?
If I can solve Sudoku can I solve Travelling Salesman Problem(TSP)? If yes, how?
The difference between「N分で」and「後N分で」
Are there other languages, besides English, where the indefinite (or definite) article varies based on sound?
Are all passive ability checks floors for active ability checks?
Can I use USB data pins as power source
In a future war, an old lady is trying to raise a boy but one of the weapons has made everyone deaf
Instead of Universal Basic Income, why not Universal Basic NEEDS?
How to read the value of this capacitor?
What did Alexander Pope mean by "Expletives their feeble Aid do join"?
Python if-else code style for reduced code for rounding floats
2019 Community Moderator ElectionIs floating point math broken?How do I parse a string to a float or int in Python?Printing increments of 0.1 in c#How can I force division to be floating point? Division keeps rounding down to 0?Double increments in JavaPut integers from stdin in listSelecting lines of a file specified by a list of stringsPerfect ROC curve but imperfect prediction accuracyFor loop break doesn't work PythonHow to classify observations based on their covariates in dataframe and numpy?Parse dataframe with specific column and write to sheets in one excel file
Is there any shorter, more legible code style to solve this problem?
I am trying to classify some float values into interregional folders.
def classify(value):
if value < -0.85 and value >= -0.95:
ts_folder = r'-0.9'
elif value < -0.75 and value >= -0.85:
ts_folder = r'-0.8'
elif value < -0.65 and value >= -0.75:
ts_folder = r'-0.7'
elif value < -0.55 and value >= -0.65:
ts_folder = r'-0.6'
elif value < -0.45 and value >= -0.55:
ts_folder = r'-0.5'
elif value < -0.35 and value >= -0.45:
ts_folder = r'-0.4'
elif value < -0.25 and value >= -0.35:
ts_folder = r'-0.3'
elif value < -0.15 and value >= -0.25:
ts_folder = r'-0.2'
elif value < -0.05 and value >= -0.15:
ts_folder = r'-0.1'
elif value < 0.05 and value >= -0.05:
ts_folder = r'.0'
elif value < 0.15 and value >= 0.05:
ts_folder = r'.1'
elif value < 0.25 and value >= 0.15:
ts_folder = r'.2'
elif value < 0.35 and value >= 0.25:
ts_folder = r'.3'
elif value < 0.45 and value >= 0.35:
ts_folder = r'.4'
elif value < 0.55 and value >= 0.45:
ts_folder = r'.5'
elif value < 0.65 and value >= 0.55:
ts_folder = r'.6'
elif value < 0.75 and value >= 0.65:
ts_folder = r'.7'
elif value < 0.85 and value >= 0.75:
ts_folder = r'.8'
elif value < 0.95 and value >= 0.85:
ts_folder = r'.9'
return ts_folder
python floating-point rounding number-formatting
|
show 2 more comments
Is there any shorter, more legible code style to solve this problem?
I am trying to classify some float values into interregional folders.
def classify(value):
if value < -0.85 and value >= -0.95:
ts_folder = r'-0.9'
elif value < -0.75 and value >= -0.85:
ts_folder = r'-0.8'
elif value < -0.65 and value >= -0.75:
ts_folder = r'-0.7'
elif value < -0.55 and value >= -0.65:
ts_folder = r'-0.6'
elif value < -0.45 and value >= -0.55:
ts_folder = r'-0.5'
elif value < -0.35 and value >= -0.45:
ts_folder = r'-0.4'
elif value < -0.25 and value >= -0.35:
ts_folder = r'-0.3'
elif value < -0.15 and value >= -0.25:
ts_folder = r'-0.2'
elif value < -0.05 and value >= -0.15:
ts_folder = r'-0.1'
elif value < 0.05 and value >= -0.05:
ts_folder = r'.0'
elif value < 0.15 and value >= 0.05:
ts_folder = r'.1'
elif value < 0.25 and value >= 0.15:
ts_folder = r'.2'
elif value < 0.35 and value >= 0.25:
ts_folder = r'.3'
elif value < 0.45 and value >= 0.35:
ts_folder = r'.4'
elif value < 0.55 and value >= 0.45:
ts_folder = r'.5'
elif value < 0.65 and value >= 0.55:
ts_folder = r'.6'
elif value < 0.75 and value >= 0.65:
ts_folder = r'.7'
elif value < 0.85 and value >= 0.75:
ts_folder = r'.8'
elif value < 0.95 and value >= 0.85:
ts_folder = r'.9'
return ts_folder
python floating-point rounding number-formatting
44
That is the longest code for a rounding function I've ever seen!
– Aran-Fey
12 hours ago
I agree with @Aran-Fey. That thing's huge, OP!
– connectyourcharger
12 hours ago
That's an example. In my experiment, diffence isn't always 0.5. round() is a good way in this case but not always work for me
– Kuang 鄺世銘
12 hours ago
6
At the very least, use chained comparisons:-0.95 <= value < -0.85
instead of `value < -0.85 and value >= -0.95
– chepner
11 hours ago
2
It's a great way to hide bugs!ts_folder
is undefined for values larger than0.95
or smaller than-0.85
. Also, the result for-0.45
and-0.35
differ by0.2
.
– Eric Duminil
6 hours ago
|
show 2 more comments
Is there any shorter, more legible code style to solve this problem?
I am trying to classify some float values into interregional folders.
def classify(value):
if value < -0.85 and value >= -0.95:
ts_folder = r'-0.9'
elif value < -0.75 and value >= -0.85:
ts_folder = r'-0.8'
elif value < -0.65 and value >= -0.75:
ts_folder = r'-0.7'
elif value < -0.55 and value >= -0.65:
ts_folder = r'-0.6'
elif value < -0.45 and value >= -0.55:
ts_folder = r'-0.5'
elif value < -0.35 and value >= -0.45:
ts_folder = r'-0.4'
elif value < -0.25 and value >= -0.35:
ts_folder = r'-0.3'
elif value < -0.15 and value >= -0.25:
ts_folder = r'-0.2'
elif value < -0.05 and value >= -0.15:
ts_folder = r'-0.1'
elif value < 0.05 and value >= -0.05:
ts_folder = r'.0'
elif value < 0.15 and value >= 0.05:
ts_folder = r'.1'
elif value < 0.25 and value >= 0.15:
ts_folder = r'.2'
elif value < 0.35 and value >= 0.25:
ts_folder = r'.3'
elif value < 0.45 and value >= 0.35:
ts_folder = r'.4'
elif value < 0.55 and value >= 0.45:
ts_folder = r'.5'
elif value < 0.65 and value >= 0.55:
ts_folder = r'.6'
elif value < 0.75 and value >= 0.65:
ts_folder = r'.7'
elif value < 0.85 and value >= 0.75:
ts_folder = r'.8'
elif value < 0.95 and value >= 0.85:
ts_folder = r'.9'
return ts_folder
python floating-point rounding number-formatting
Is there any shorter, more legible code style to solve this problem?
I am trying to classify some float values into interregional folders.
def classify(value):
if value < -0.85 and value >= -0.95:
ts_folder = r'-0.9'
elif value < -0.75 and value >= -0.85:
ts_folder = r'-0.8'
elif value < -0.65 and value >= -0.75:
ts_folder = r'-0.7'
elif value < -0.55 and value >= -0.65:
ts_folder = r'-0.6'
elif value < -0.45 and value >= -0.55:
ts_folder = r'-0.5'
elif value < -0.35 and value >= -0.45:
ts_folder = r'-0.4'
elif value < -0.25 and value >= -0.35:
ts_folder = r'-0.3'
elif value < -0.15 and value >= -0.25:
ts_folder = r'-0.2'
elif value < -0.05 and value >= -0.15:
ts_folder = r'-0.1'
elif value < 0.05 and value >= -0.05:
ts_folder = r'.0'
elif value < 0.15 and value >= 0.05:
ts_folder = r'.1'
elif value < 0.25 and value >= 0.15:
ts_folder = r'.2'
elif value < 0.35 and value >= 0.25:
ts_folder = r'.3'
elif value < 0.45 and value >= 0.35:
ts_folder = r'.4'
elif value < 0.55 and value >= 0.45:
ts_folder = r'.5'
elif value < 0.65 and value >= 0.55:
ts_folder = r'.6'
elif value < 0.75 and value >= 0.65:
ts_folder = r'.7'
elif value < 0.85 and value >= 0.75:
ts_folder = r'.8'
elif value < 0.95 and value >= 0.85:
ts_folder = r'.9'
return ts_folder
python floating-point rounding number-formatting
python floating-point rounding number-formatting
edited 29 mins ago
smci
15.3k677108
15.3k677108
asked 12 hours ago
Kuang 鄺世銘Kuang 鄺世銘
826
826
44
That is the longest code for a rounding function I've ever seen!
– Aran-Fey
12 hours ago
I agree with @Aran-Fey. That thing's huge, OP!
– connectyourcharger
12 hours ago
That's an example. In my experiment, diffence isn't always 0.5. round() is a good way in this case but not always work for me
– Kuang 鄺世銘
12 hours ago
6
At the very least, use chained comparisons:-0.95 <= value < -0.85
instead of `value < -0.85 and value >= -0.95
– chepner
11 hours ago
2
It's a great way to hide bugs!ts_folder
is undefined for values larger than0.95
or smaller than-0.85
. Also, the result for-0.45
and-0.35
differ by0.2
.
– Eric Duminil
6 hours ago
|
show 2 more comments
44
That is the longest code for a rounding function I've ever seen!
– Aran-Fey
12 hours ago
I agree with @Aran-Fey. That thing's huge, OP!
– connectyourcharger
12 hours ago
That's an example. In my experiment, diffence isn't always 0.5. round() is a good way in this case but not always work for me
– Kuang 鄺世銘
12 hours ago
6
At the very least, use chained comparisons:-0.95 <= value < -0.85
instead of `value < -0.85 and value >= -0.95
– chepner
11 hours ago
2
It's a great way to hide bugs!ts_folder
is undefined for values larger than0.95
or smaller than-0.85
. Also, the result for-0.45
and-0.35
differ by0.2
.
– Eric Duminil
6 hours ago
44
44
That is the longest code for a rounding function I've ever seen!
– Aran-Fey
12 hours ago
That is the longest code for a rounding function I've ever seen!
– Aran-Fey
12 hours ago
I agree with @Aran-Fey. That thing's huge, OP!
– connectyourcharger
12 hours ago
I agree with @Aran-Fey. That thing's huge, OP!
– connectyourcharger
12 hours ago
That's an example. In my experiment, diffence isn't always 0.5. round() is a good way in this case but not always work for me
– Kuang 鄺世銘
12 hours ago
That's an example. In my experiment, diffence isn't always 0.5. round() is a good way in this case but not always work for me
– Kuang 鄺世銘
12 hours ago
6
6
At the very least, use chained comparisons:
-0.95 <= value < -0.85
instead of `value < -0.85 and value >= -0.95– chepner
11 hours ago
At the very least, use chained comparisons:
-0.95 <= value < -0.85
instead of `value < -0.85 and value >= -0.95– chepner
11 hours ago
2
2
It's a great way to hide bugs!
ts_folder
is undefined for values larger than 0.95
or smaller than -0.85
. Also, the result for -0.45
and -0.35
differ by 0.2
.– Eric Duminil
6 hours ago
It's a great way to hide bugs!
ts_folder
is undefined for values larger than 0.95
or smaller than -0.85
. Also, the result for -0.45
and -0.35
differ by 0.2
.– Eric Duminil
6 hours ago
|
show 2 more comments
11 Answers
11
active
oldest
votes
Specific solution
There is no real general solution, but in your case you can use the following expression.
ts_folder = r':.1f'.format(round(value, 1))
General solution
If you actually need some kind of generalization, notice that any non-linear pattern will cause trouble. Although, there is a way to shorten the code.
def classify(key, intervals):
for lo, hi, value in intervals:
if lo <= key < hi:
return value
else:
... # return a default value or None
# A list of tuples (lo, hi, key) which associates any value in the lo to hi interval to key
intervals = [
(value / 10 - 0.05, value / 10 + 0.05, r':.1f'.format(value / 10))
for value in range(-9, 10)
]
value = -0.73
ts_folder = classify(value, intervals) # r'-0.7'
Notice that the above is still not totally safe from some float rounding error. You can add precision by manually typing down the intervals
list instead of using a comprehension.
2
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified tor':.1f'.format(folder_value)
.
– Aran-Fey
12 hours ago
1
Note that the OP hadif lo <=key < hi
.
– Martin Bonner
8 hours ago
1
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomesfor hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
1
Floats comparison are tricky. On my computer, your specific solution returns different values for[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.
– Eric Duminil
6 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
|
show 1 more comment
The bisect module will do exactly the right lookup for finding the right bin from a list of breakpoints. In fact, the example in the documentation is exactly a case like this:
The bisect() function is generally useful for categorizing numeric data. This example uses bisect() to look up a letter grade for an exam total (say) based on a set of ordered numeric breakpoints: 85 and up is an ‘A’, 75..84 is a ‘B’, etc.
>>> grades = "FEDCBA"
>>> breakpoints = [30, 44, 66, 75, 85]
>>> from bisect import bisect
>>> def grade(total):
... return grades[bisect(breakpoints, total)]
>>> grade(66)
'C'
>>> map(grade, [33, 99, 77, 44, 12, 88])
['E', 'A', 'B', 'D', 'F', 'A']
Instead of a string for the value lookups, you'd want a list of strings for the exact folder names you need for each range of values. For example:
breakpoints = [-0.85, -0.75, -0.65]
folders = [r'-0.9', r'-0.8', r'-0.7']
foldername = folders[bisect(breakpoints, -0.72)]
If you can automate even part of this table generation (using round()
, or something similar), of course you should.
add a comment |
All answers revolve around rounding, which seems to be fine in this case, but just for the sake of argument I'd like to also point out a cool python use of dictionaries which is often described as an alternative to other languages switch(es) and that in turn allow for arbitrary values.
ranges =
(-0.85, -0.95): r'-0.9',
(-0.75, -0.85): r'-0.8',
(-0.65, -0.75): r'-0.7',
(-0.55, -0.65): r'-0.6'
...
def classify (value):
for (ceiling, floor), rounded_value in ranges.items():
if floor <= value < ceiling:
return rounded_value
Output:
>>> classify(-0.78)
-0.8
15
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless__getitem__
access).
– bruno desthuilliers
10 hours ago
1
@chepner By editing this code you have made it not work; it indexes intoranges
withcurrent_value
which is not defined (because you deleted it).
– Arthur Tacca
8 hours ago
add a comment |
Why not just use the round()
built-in ?
ts_folder = "\" + str(round(value + 1e-16, 1))
(The +1e-16
etc is because floats like .15
are by default rounded to .1
, not .2
)
More on round()
It doesn't seem to work for[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.
– Eric Duminil
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
add a comment |
One of the first rules with a block of code like this, is to always make the comparisons be in the same direction. So instead of
elif value < -0.75 and value >= -0.85:
write
elif -0.85 <= value and value < -0.75:
At this point you can observe that python allows chaining of comparisons, so you can write:
elif -0.85 <= value < -0.75:
Which is an improvement itself. Alternatively, you can observe this is an ordered list of comparisons, so if you add in an initial comparisons, you can just write
if value < -0.95:
ts_folder = ''
elif value < -0.85:
ts_folder = r'-0.9'
elif value < -0.75:
ts_folder = r'-0.8'
elif value < -0.65:
ts_folder = r'-0.7'
elif value < -0.55:
ts_folder = r'-0.6'
elif value < -0.45:
ts_folder = r'-0.5'
elif value < -0.35:
ts_folder = r'-0.4'
elif value < -0.25:
ts_folder = r'-0.3'
elif value < -0.15:
ts_folder = r'-0.2'
elif value < -0.05:
ts_folder = r'-0.1'
elif value < 0.05:
ts_folder = r'.0'
elif value < 0.15:
ts_folder = r'.1'
elif value < 0.25:
ts_folder = r'.2'
elif value < 0.35:
ts_folder = r'.3'
elif value < 0.45:
ts_folder = r'.4'
elif value < 0.55:
ts_folder = r'.5'
elif value < 0.65:
ts_folder = r'.6'
elif value < 0.75:
ts_folder = r'.7'
elif value < 0.85:
ts_folder = r'.8'
elif value < 0.95:
ts_folder = r'.9'
else:
ts_folder = ''
That's still quite long, but a) it's a lot more readable; b) it has explicit code to handle value < -0.95 or 0.95 <= value
this is one of the most useful answers here
– aaaaaa
1 hour ago
add a comment |
Actually in Python 3 .85
will be round to .8
. As per the question .85
should be round to .9
.
Can you try the following:
round2 = lambda x, y=None: round(x+1e-15, y)
ts_folder = r''.format(str(round2(value, 1)))
Output:
>>> round2(.85, 1)
0.9
>>> round2(-.85, 1)
-0.8
add a comment |
Take a look at the round()
function in python. Maybe you can work it out without the if.
With this function you can specify the number of digits you need to keep.
For example :
x = round(5.76543, 2)
print(x)
That code will print 5.77
2
Please try and answer with a clear example
– AJS
12 hours ago
add a comment |
How about turning it into a loop?
def classify(value):
i = -5
while i < 95:
if value < (i + 10) / 100.0 and value >= i / 100.0:
return '\' + repr((i + 5) / 100.0)
i += 10
it's not efficient by any means, but it's equivalent to what you have, just shorter.
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
add a comment |
from decimal import Decimal
def classify(value):
number = Decimal(value)
result = "%.2f" % (number)
return Decimal(round(float(result), 2))
3
star imports are bad practice.
– bruno desthuilliers
10 hours ago
add a comment |
You don't need the and value >= -.85
in elif value < -0.75 and value >= -0.85:
; if the value isn't greater than or equal to -.85, then you won't reach the elif. You can also just turn all the elif
s into if
by having each one return immediately.
In this case, since you have the boundaries at regular intervals, you can just round (in the general case of regular intervals, you may have to divide and then round, for instance if the intervals are at every three units, then you would divide the number by three and round). In the general case, it's faster to store the boundaries in a tree structure, and then do a binary search for where the item goes.
Doing a binary search explicitly would be something like this:
def classify(value):
if value < -.05:
if value < -.45:
if value < -.65:
if value < -.85:
if value < -.95:
return None
return r'-0.9'
if value < -.75:
return r'-0.8'
return r'-0.7'
...
Although this code is harder to read than yours, it runs in time logarithmic rather than linear with respect to the number of boundaries.
If the number of items is significantly larger than the number of boundaries, it would probably be faster to actually create a tree of the items, and insert the boundaries.
You could also create a list, sort it, and then look at the index. For instance, compare (sorted([(_-9.5)/10 for _ in range(20)]+[x]).index(x)-9)/10
to your function.
add a comment |
Try something like this, if you don't like loops:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_folder = [ r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
idx = [value >= end for end in endpts].index(False)
if not idx:
raise ValueError('Value outside of range')
return ts_folder[idx-1]
Of course, the loop is just "hidden" in the list comprehension.
Obviously, in this example, it would be better to generate endpts
and ts_fol
programmatically rather than writing them all out, but you indicated that in the real situation the endpoints and values aren't so straightforward.
This raises a ValueError
if value
≥ 0.95 (because False
is not found in the list comprehension) or if value
< -0.95 (because then idx
is 0); the original version raises a UnboundLocalError
in these cases.
You could also save three lines and skip a few comparisons by doing this:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_fol = [ None, r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
return next((ts for ts, end in zip(ts_fol, endpts) if value < end), None)
This version returns None
rather than raising exceptions for any value outside the bounds.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55180829%2fpython-if-else-code-style-for-reduced-code-for-rounding-floats%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
11 Answers
11
active
oldest
votes
11 Answers
11
active
oldest
votes
active
oldest
votes
active
oldest
votes
Specific solution
There is no real general solution, but in your case you can use the following expression.
ts_folder = r':.1f'.format(round(value, 1))
General solution
If you actually need some kind of generalization, notice that any non-linear pattern will cause trouble. Although, there is a way to shorten the code.
def classify(key, intervals):
for lo, hi, value in intervals:
if lo <= key < hi:
return value
else:
... # return a default value or None
# A list of tuples (lo, hi, key) which associates any value in the lo to hi interval to key
intervals = [
(value / 10 - 0.05, value / 10 + 0.05, r':.1f'.format(value / 10))
for value in range(-9, 10)
]
value = -0.73
ts_folder = classify(value, intervals) # r'-0.7'
Notice that the above is still not totally safe from some float rounding error. You can add precision by manually typing down the intervals
list instead of using a comprehension.
2
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified tor':.1f'.format(folder_value)
.
– Aran-Fey
12 hours ago
1
Note that the OP hadif lo <=key < hi
.
– Martin Bonner
8 hours ago
1
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomesfor hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
1
Floats comparison are tricky. On my computer, your specific solution returns different values for[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.
– Eric Duminil
6 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
|
show 1 more comment
Specific solution
There is no real general solution, but in your case you can use the following expression.
ts_folder = r':.1f'.format(round(value, 1))
General solution
If you actually need some kind of generalization, notice that any non-linear pattern will cause trouble. Although, there is a way to shorten the code.
def classify(key, intervals):
for lo, hi, value in intervals:
if lo <= key < hi:
return value
else:
... # return a default value or None
# A list of tuples (lo, hi, key) which associates any value in the lo to hi interval to key
intervals = [
(value / 10 - 0.05, value / 10 + 0.05, r':.1f'.format(value / 10))
for value in range(-9, 10)
]
value = -0.73
ts_folder = classify(value, intervals) # r'-0.7'
Notice that the above is still not totally safe from some float rounding error. You can add precision by manually typing down the intervals
list instead of using a comprehension.
2
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified tor':.1f'.format(folder_value)
.
– Aran-Fey
12 hours ago
1
Note that the OP hadif lo <=key < hi
.
– Martin Bonner
8 hours ago
1
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomesfor hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
1
Floats comparison are tricky. On my computer, your specific solution returns different values for[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.
– Eric Duminil
6 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
|
show 1 more comment
Specific solution
There is no real general solution, but in your case you can use the following expression.
ts_folder = r':.1f'.format(round(value, 1))
General solution
If you actually need some kind of generalization, notice that any non-linear pattern will cause trouble. Although, there is a way to shorten the code.
def classify(key, intervals):
for lo, hi, value in intervals:
if lo <= key < hi:
return value
else:
... # return a default value or None
# A list of tuples (lo, hi, key) which associates any value in the lo to hi interval to key
intervals = [
(value / 10 - 0.05, value / 10 + 0.05, r':.1f'.format(value / 10))
for value in range(-9, 10)
]
value = -0.73
ts_folder = classify(value, intervals) # r'-0.7'
Notice that the above is still not totally safe from some float rounding error. You can add precision by manually typing down the intervals
list instead of using a comprehension.
Specific solution
There is no real general solution, but in your case you can use the following expression.
ts_folder = r':.1f'.format(round(value, 1))
General solution
If you actually need some kind of generalization, notice that any non-linear pattern will cause trouble. Although, there is a way to shorten the code.
def classify(key, intervals):
for lo, hi, value in intervals:
if lo <= key < hi:
return value
else:
... # return a default value or None
# A list of tuples (lo, hi, key) which associates any value in the lo to hi interval to key
intervals = [
(value / 10 - 0.05, value / 10 + 0.05, r':.1f'.format(value / 10))
for value in range(-9, 10)
]
value = -0.73
ts_folder = classify(value, intervals) # r'-0.7'
Notice that the above is still not totally safe from some float rounding error. You can add precision by manually typing down the intervals
list instead of using a comprehension.
edited 3 hours ago
answered 12 hours ago
Olivier MelançonOlivier Melançon
13.9k21942
13.9k21942
2
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified tor':.1f'.format(folder_value)
.
– Aran-Fey
12 hours ago
1
Note that the OP hadif lo <=key < hi
.
– Martin Bonner
8 hours ago
1
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomesfor hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
1
Floats comparison are tricky. On my computer, your specific solution returns different values for[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.
– Eric Duminil
6 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
|
show 1 more comment
2
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified tor':.1f'.format(folder_value)
.
– Aran-Fey
12 hours ago
1
Note that the OP hadif lo <=key < hi
.
– Martin Bonner
8 hours ago
1
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomesfor hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
1
Floats comparison are tricky. On my computer, your specific solution returns different values for[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.
– Eric Duminil
6 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
2
2
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified to r':.1f'.format(folder_value)
.– Aran-Fey
12 hours ago
r ''.format(str(folder_value)[:3 if folder_value >= 0 else 4])
can be simplified to r':.1f'.format(folder_value)
.– Aran-Fey
12 hours ago
1
1
Note that the OP had
if lo <=key < hi
.– Martin Bonner
8 hours ago
Note that the OP had
if lo <=key < hi
.– Martin Bonner
8 hours ago
1
1
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomes
for hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
If the intervals are supposed to be contiguous, you can require that they are supplied sorted (low to high), and then just have the intervals be (hi, value), and then the loop becomes
for hi, value in intervals: if key < hi: return value
– Martin Bonner
8 hours ago
1
1
Floats comparison are tricky. On my computer, your specific solution returns different values for
[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.– Eric Duminil
6 hours ago
Floats comparison are tricky. On my computer, your specific solution returns different values for
[-0.75, -0.65, -0.55, -0.45, -0.05, -0.04, -0.03, -0.02, -0.01, 0.15, 0.25, 0.35, 0.85]
compared to OP's code.– Eric Duminil
6 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
@EricDuminill yes, that is why I suggest providing them as literals, without using a list-comprehension.
– Olivier Melançon
4 hours ago
|
show 1 more comment
The bisect module will do exactly the right lookup for finding the right bin from a list of breakpoints. In fact, the example in the documentation is exactly a case like this:
The bisect() function is generally useful for categorizing numeric data. This example uses bisect() to look up a letter grade for an exam total (say) based on a set of ordered numeric breakpoints: 85 and up is an ‘A’, 75..84 is a ‘B’, etc.
>>> grades = "FEDCBA"
>>> breakpoints = [30, 44, 66, 75, 85]
>>> from bisect import bisect
>>> def grade(total):
... return grades[bisect(breakpoints, total)]
>>> grade(66)
'C'
>>> map(grade, [33, 99, 77, 44, 12, 88])
['E', 'A', 'B', 'D', 'F', 'A']
Instead of a string for the value lookups, you'd want a list of strings for the exact folder names you need for each range of values. For example:
breakpoints = [-0.85, -0.75, -0.65]
folders = [r'-0.9', r'-0.8', r'-0.7']
foldername = folders[bisect(breakpoints, -0.72)]
If you can automate even part of this table generation (using round()
, or something similar), of course you should.
add a comment |
The bisect module will do exactly the right lookup for finding the right bin from a list of breakpoints. In fact, the example in the documentation is exactly a case like this:
The bisect() function is generally useful for categorizing numeric data. This example uses bisect() to look up a letter grade for an exam total (say) based on a set of ordered numeric breakpoints: 85 and up is an ‘A’, 75..84 is a ‘B’, etc.
>>> grades = "FEDCBA"
>>> breakpoints = [30, 44, 66, 75, 85]
>>> from bisect import bisect
>>> def grade(total):
... return grades[bisect(breakpoints, total)]
>>> grade(66)
'C'
>>> map(grade, [33, 99, 77, 44, 12, 88])
['E', 'A', 'B', 'D', 'F', 'A']
Instead of a string for the value lookups, you'd want a list of strings for the exact folder names you need for each range of values. For example:
breakpoints = [-0.85, -0.75, -0.65]
folders = [r'-0.9', r'-0.8', r'-0.7']
foldername = folders[bisect(breakpoints, -0.72)]
If you can automate even part of this table generation (using round()
, or something similar), of course you should.
add a comment |
The bisect module will do exactly the right lookup for finding the right bin from a list of breakpoints. In fact, the example in the documentation is exactly a case like this:
The bisect() function is generally useful for categorizing numeric data. This example uses bisect() to look up a letter grade for an exam total (say) based on a set of ordered numeric breakpoints: 85 and up is an ‘A’, 75..84 is a ‘B’, etc.
>>> grades = "FEDCBA"
>>> breakpoints = [30, 44, 66, 75, 85]
>>> from bisect import bisect
>>> def grade(total):
... return grades[bisect(breakpoints, total)]
>>> grade(66)
'C'
>>> map(grade, [33, 99, 77, 44, 12, 88])
['E', 'A', 'B', 'D', 'F', 'A']
Instead of a string for the value lookups, you'd want a list of strings for the exact folder names you need for each range of values. For example:
breakpoints = [-0.85, -0.75, -0.65]
folders = [r'-0.9', r'-0.8', r'-0.7']
foldername = folders[bisect(breakpoints, -0.72)]
If you can automate even part of this table generation (using round()
, or something similar), of course you should.
The bisect module will do exactly the right lookup for finding the right bin from a list of breakpoints. In fact, the example in the documentation is exactly a case like this:
The bisect() function is generally useful for categorizing numeric data. This example uses bisect() to look up a letter grade for an exam total (say) based on a set of ordered numeric breakpoints: 85 and up is an ‘A’, 75..84 is a ‘B’, etc.
>>> grades = "FEDCBA"
>>> breakpoints = [30, 44, 66, 75, 85]
>>> from bisect import bisect
>>> def grade(total):
... return grades[bisect(breakpoints, total)]
>>> grade(66)
'C'
>>> map(grade, [33, 99, 77, 44, 12, 88])
['E', 'A', 'B', 'D', 'F', 'A']
Instead of a string for the value lookups, you'd want a list of strings for the exact folder names you need for each range of values. For example:
breakpoints = [-0.85, -0.75, -0.65]
folders = [r'-0.9', r'-0.8', r'-0.7']
foldername = folders[bisect(breakpoints, -0.72)]
If you can automate even part of this table generation (using round()
, or something similar), of course you should.
answered 6 hours ago
PeterPeter
11.5k1846
11.5k1846
add a comment |
add a comment |
All answers revolve around rounding, which seems to be fine in this case, but just for the sake of argument I'd like to also point out a cool python use of dictionaries which is often described as an alternative to other languages switch(es) and that in turn allow for arbitrary values.
ranges =
(-0.85, -0.95): r'-0.9',
(-0.75, -0.85): r'-0.8',
(-0.65, -0.75): r'-0.7',
(-0.55, -0.65): r'-0.6'
...
def classify (value):
for (ceiling, floor), rounded_value in ranges.items():
if floor <= value < ceiling:
return rounded_value
Output:
>>> classify(-0.78)
-0.8
15
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless__getitem__
access).
– bruno desthuilliers
10 hours ago
1
@chepner By editing this code you have made it not work; it indexes intoranges
withcurrent_value
which is not defined (because you deleted it).
– Arthur Tacca
8 hours ago
add a comment |
All answers revolve around rounding, which seems to be fine in this case, but just for the sake of argument I'd like to also point out a cool python use of dictionaries which is often described as an alternative to other languages switch(es) and that in turn allow for arbitrary values.
ranges =
(-0.85, -0.95): r'-0.9',
(-0.75, -0.85): r'-0.8',
(-0.65, -0.75): r'-0.7',
(-0.55, -0.65): r'-0.6'
...
def classify (value):
for (ceiling, floor), rounded_value in ranges.items():
if floor <= value < ceiling:
return rounded_value
Output:
>>> classify(-0.78)
-0.8
15
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless__getitem__
access).
– bruno desthuilliers
10 hours ago
1
@chepner By editing this code you have made it not work; it indexes intoranges
withcurrent_value
which is not defined (because you deleted it).
– Arthur Tacca
8 hours ago
add a comment |
All answers revolve around rounding, which seems to be fine in this case, but just for the sake of argument I'd like to also point out a cool python use of dictionaries which is often described as an alternative to other languages switch(es) and that in turn allow for arbitrary values.
ranges =
(-0.85, -0.95): r'-0.9',
(-0.75, -0.85): r'-0.8',
(-0.65, -0.75): r'-0.7',
(-0.55, -0.65): r'-0.6'
...
def classify (value):
for (ceiling, floor), rounded_value in ranges.items():
if floor <= value < ceiling:
return rounded_value
Output:
>>> classify(-0.78)
-0.8
All answers revolve around rounding, which seems to be fine in this case, but just for the sake of argument I'd like to also point out a cool python use of dictionaries which is often described as an alternative to other languages switch(es) and that in turn allow for arbitrary values.
ranges =
(-0.85, -0.95): r'-0.9',
(-0.75, -0.85): r'-0.8',
(-0.65, -0.75): r'-0.7',
(-0.55, -0.65): r'-0.6'
...
def classify (value):
for (ceiling, floor), rounded_value in ranges.items():
if floor <= value < ceiling:
return rounded_value
Output:
>>> classify(-0.78)
-0.8
edited 8 hours ago
chepner
257k34247339
257k34247339
answered 11 hours ago
Hirabayashi TaroHirabayashi Taro
533311
533311
15
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless__getitem__
access).
– bruno desthuilliers
10 hours ago
1
@chepner By editing this code you have made it not work; it indexes intoranges
withcurrent_value
which is not defined (because you deleted it).
– Arthur Tacca
8 hours ago
add a comment |
15
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless__getitem__
access).
– bruno desthuilliers
10 hours ago
1
@chepner By editing this code you have made it not work; it indexes intoranges
withcurrent_value
which is not defined (because you deleted it).
– Arthur Tacca
8 hours ago
15
15
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of
(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless __getitem__
access).– bruno desthuilliers
10 hours ago
In this case you're NOT using the "dict dispatch" trick - you're doing a sequential scan, so you'd get the exact same result with a list of
(start, stop, val)
tuples (but with the added overhead of creating a dict and doing a useless __getitem__
access).– bruno desthuilliers
10 hours ago
1
1
@chepner By editing this code you have made it not work; it indexes into
ranges
with current_value
which is not defined (because you deleted it).– Arthur Tacca
8 hours ago
@chepner By editing this code you have made it not work; it indexes into
ranges
with current_value
which is not defined (because you deleted it).– Arthur Tacca
8 hours ago
add a comment |
Why not just use the round()
built-in ?
ts_folder = "\" + str(round(value + 1e-16, 1))
(The +1e-16
etc is because floats like .15
are by default rounded to .1
, not .2
)
More on round()
It doesn't seem to work for[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.
– Eric Duminil
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
add a comment |
Why not just use the round()
built-in ?
ts_folder = "\" + str(round(value + 1e-16, 1))
(The +1e-16
etc is because floats like .15
are by default rounded to .1
, not .2
)
More on round()
It doesn't seem to work for[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.
– Eric Duminil
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
add a comment |
Why not just use the round()
built-in ?
ts_folder = "\" + str(round(value + 1e-16, 1))
(The +1e-16
etc is because floats like .15
are by default rounded to .1
, not .2
)
More on round()
Why not just use the round()
built-in ?
ts_folder = "\" + str(round(value + 1e-16, 1))
(The +1e-16
etc is because floats like .15
are by default rounded to .1
, not .2
)
More on round()
edited 5 hours ago
answered 12 hours ago
FukiyelFukiyel
902216
902216
It doesn't seem to work for[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.
– Eric Duminil
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
add a comment |
It doesn't seem to work for[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.
– Eric Duminil
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
It doesn't seem to work for
[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.– Eric Duminil
5 hours ago
It doesn't seem to work for
[-0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, -0.04, -0.03, -0.02, -0.01, 0.0]
, compared to OP's code. I'm not sure if it's a bug or a feature.– Eric Duminil
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
Oh my bad, should be good now
– Fukiyel
5 hours ago
add a comment |
One of the first rules with a block of code like this, is to always make the comparisons be in the same direction. So instead of
elif value < -0.75 and value >= -0.85:
write
elif -0.85 <= value and value < -0.75:
At this point you can observe that python allows chaining of comparisons, so you can write:
elif -0.85 <= value < -0.75:
Which is an improvement itself. Alternatively, you can observe this is an ordered list of comparisons, so if you add in an initial comparisons, you can just write
if value < -0.95:
ts_folder = ''
elif value < -0.85:
ts_folder = r'-0.9'
elif value < -0.75:
ts_folder = r'-0.8'
elif value < -0.65:
ts_folder = r'-0.7'
elif value < -0.55:
ts_folder = r'-0.6'
elif value < -0.45:
ts_folder = r'-0.5'
elif value < -0.35:
ts_folder = r'-0.4'
elif value < -0.25:
ts_folder = r'-0.3'
elif value < -0.15:
ts_folder = r'-0.2'
elif value < -0.05:
ts_folder = r'-0.1'
elif value < 0.05:
ts_folder = r'.0'
elif value < 0.15:
ts_folder = r'.1'
elif value < 0.25:
ts_folder = r'.2'
elif value < 0.35:
ts_folder = r'.3'
elif value < 0.45:
ts_folder = r'.4'
elif value < 0.55:
ts_folder = r'.5'
elif value < 0.65:
ts_folder = r'.6'
elif value < 0.75:
ts_folder = r'.7'
elif value < 0.85:
ts_folder = r'.8'
elif value < 0.95:
ts_folder = r'.9'
else:
ts_folder = ''
That's still quite long, but a) it's a lot more readable; b) it has explicit code to handle value < -0.95 or 0.95 <= value
this is one of the most useful answers here
– aaaaaa
1 hour ago
add a comment |
One of the first rules with a block of code like this, is to always make the comparisons be in the same direction. So instead of
elif value < -0.75 and value >= -0.85:
write
elif -0.85 <= value and value < -0.75:
At this point you can observe that python allows chaining of comparisons, so you can write:
elif -0.85 <= value < -0.75:
Which is an improvement itself. Alternatively, you can observe this is an ordered list of comparisons, so if you add in an initial comparisons, you can just write
if value < -0.95:
ts_folder = ''
elif value < -0.85:
ts_folder = r'-0.9'
elif value < -0.75:
ts_folder = r'-0.8'
elif value < -0.65:
ts_folder = r'-0.7'
elif value < -0.55:
ts_folder = r'-0.6'
elif value < -0.45:
ts_folder = r'-0.5'
elif value < -0.35:
ts_folder = r'-0.4'
elif value < -0.25:
ts_folder = r'-0.3'
elif value < -0.15:
ts_folder = r'-0.2'
elif value < -0.05:
ts_folder = r'-0.1'
elif value < 0.05:
ts_folder = r'.0'
elif value < 0.15:
ts_folder = r'.1'
elif value < 0.25:
ts_folder = r'.2'
elif value < 0.35:
ts_folder = r'.3'
elif value < 0.45:
ts_folder = r'.4'
elif value < 0.55:
ts_folder = r'.5'
elif value < 0.65:
ts_folder = r'.6'
elif value < 0.75:
ts_folder = r'.7'
elif value < 0.85:
ts_folder = r'.8'
elif value < 0.95:
ts_folder = r'.9'
else:
ts_folder = ''
That's still quite long, but a) it's a lot more readable; b) it has explicit code to handle value < -0.95 or 0.95 <= value
this is one of the most useful answers here
– aaaaaa
1 hour ago
add a comment |
One of the first rules with a block of code like this, is to always make the comparisons be in the same direction. So instead of
elif value < -0.75 and value >= -0.85:
write
elif -0.85 <= value and value < -0.75:
At this point you can observe that python allows chaining of comparisons, so you can write:
elif -0.85 <= value < -0.75:
Which is an improvement itself. Alternatively, you can observe this is an ordered list of comparisons, so if you add in an initial comparisons, you can just write
if value < -0.95:
ts_folder = ''
elif value < -0.85:
ts_folder = r'-0.9'
elif value < -0.75:
ts_folder = r'-0.8'
elif value < -0.65:
ts_folder = r'-0.7'
elif value < -0.55:
ts_folder = r'-0.6'
elif value < -0.45:
ts_folder = r'-0.5'
elif value < -0.35:
ts_folder = r'-0.4'
elif value < -0.25:
ts_folder = r'-0.3'
elif value < -0.15:
ts_folder = r'-0.2'
elif value < -0.05:
ts_folder = r'-0.1'
elif value < 0.05:
ts_folder = r'.0'
elif value < 0.15:
ts_folder = r'.1'
elif value < 0.25:
ts_folder = r'.2'
elif value < 0.35:
ts_folder = r'.3'
elif value < 0.45:
ts_folder = r'.4'
elif value < 0.55:
ts_folder = r'.5'
elif value < 0.65:
ts_folder = r'.6'
elif value < 0.75:
ts_folder = r'.7'
elif value < 0.85:
ts_folder = r'.8'
elif value < 0.95:
ts_folder = r'.9'
else:
ts_folder = ''
That's still quite long, but a) it's a lot more readable; b) it has explicit code to handle value < -0.95 or 0.95 <= value
One of the first rules with a block of code like this, is to always make the comparisons be in the same direction. So instead of
elif value < -0.75 and value >= -0.85:
write
elif -0.85 <= value and value < -0.75:
At this point you can observe that python allows chaining of comparisons, so you can write:
elif -0.85 <= value < -0.75:
Which is an improvement itself. Alternatively, you can observe this is an ordered list of comparisons, so if you add in an initial comparisons, you can just write
if value < -0.95:
ts_folder = ''
elif value < -0.85:
ts_folder = r'-0.9'
elif value < -0.75:
ts_folder = r'-0.8'
elif value < -0.65:
ts_folder = r'-0.7'
elif value < -0.55:
ts_folder = r'-0.6'
elif value < -0.45:
ts_folder = r'-0.5'
elif value < -0.35:
ts_folder = r'-0.4'
elif value < -0.25:
ts_folder = r'-0.3'
elif value < -0.15:
ts_folder = r'-0.2'
elif value < -0.05:
ts_folder = r'-0.1'
elif value < 0.05:
ts_folder = r'.0'
elif value < 0.15:
ts_folder = r'.1'
elif value < 0.25:
ts_folder = r'.2'
elif value < 0.35:
ts_folder = r'.3'
elif value < 0.45:
ts_folder = r'.4'
elif value < 0.55:
ts_folder = r'.5'
elif value < 0.65:
ts_folder = r'.6'
elif value < 0.75:
ts_folder = r'.7'
elif value < 0.85:
ts_folder = r'.8'
elif value < 0.95:
ts_folder = r'.9'
else:
ts_folder = ''
That's still quite long, but a) it's a lot more readable; b) it has explicit code to handle value < -0.95 or 0.95 <= value
edited 6 hours ago
Eric Towers
3,6191015
3,6191015
answered 8 hours ago
Martin BonnerMartin Bonner
23.5k33266
23.5k33266
this is one of the most useful answers here
– aaaaaa
1 hour ago
add a comment |
this is one of the most useful answers here
– aaaaaa
1 hour ago
this is one of the most useful answers here
– aaaaaa
1 hour ago
this is one of the most useful answers here
– aaaaaa
1 hour ago
add a comment |
Actually in Python 3 .85
will be round to .8
. As per the question .85
should be round to .9
.
Can you try the following:
round2 = lambda x, y=None: round(x+1e-15, y)
ts_folder = r''.format(str(round2(value, 1)))
Output:
>>> round2(.85, 1)
0.9
>>> round2(-.85, 1)
-0.8
add a comment |
Actually in Python 3 .85
will be round to .8
. As per the question .85
should be round to .9
.
Can you try the following:
round2 = lambda x, y=None: round(x+1e-15, y)
ts_folder = r''.format(str(round2(value, 1)))
Output:
>>> round2(.85, 1)
0.9
>>> round2(-.85, 1)
-0.8
add a comment |
Actually in Python 3 .85
will be round to .8
. As per the question .85
should be round to .9
.
Can you try the following:
round2 = lambda x, y=None: round(x+1e-15, y)
ts_folder = r''.format(str(round2(value, 1)))
Output:
>>> round2(.85, 1)
0.9
>>> round2(-.85, 1)
-0.8
Actually in Python 3 .85
will be round to .8
. As per the question .85
should be round to .9
.
Can you try the following:
round2 = lambda x, y=None: round(x+1e-15, y)
ts_folder = r''.format(str(round2(value, 1)))
Output:
>>> round2(.85, 1)
0.9
>>> round2(-.85, 1)
-0.8
answered 12 hours ago
JerilJeril
2,4411735
2,4411735
add a comment |
add a comment |
Take a look at the round()
function in python. Maybe you can work it out without the if.
With this function you can specify the number of digits you need to keep.
For example :
x = round(5.76543, 2)
print(x)
That code will print 5.77
2
Please try and answer with a clear example
– AJS
12 hours ago
add a comment |
Take a look at the round()
function in python. Maybe you can work it out without the if.
With this function you can specify the number of digits you need to keep.
For example :
x = round(5.76543, 2)
print(x)
That code will print 5.77
2
Please try and answer with a clear example
– AJS
12 hours ago
add a comment |
Take a look at the round()
function in python. Maybe you can work it out without the if.
With this function you can specify the number of digits you need to keep.
For example :
x = round(5.76543, 2)
print(x)
That code will print 5.77
Take a look at the round()
function in python. Maybe you can work it out without the if.
With this function you can specify the number of digits you need to keep.
For example :
x = round(5.76543, 2)
print(x)
That code will print 5.77
edited 4 hours ago
Olivier Melançon
13.9k21942
13.9k21942
answered 12 hours ago
MelKoutchMelKoutch
575
575
2
Please try and answer with a clear example
– AJS
12 hours ago
add a comment |
2
Please try and answer with a clear example
– AJS
12 hours ago
2
2
Please try and answer with a clear example
– AJS
12 hours ago
Please try and answer with a clear example
– AJS
12 hours ago
add a comment |
How about turning it into a loop?
def classify(value):
i = -5
while i < 95:
if value < (i + 10) / 100.0 and value >= i / 100.0:
return '\' + repr((i + 5) / 100.0)
i += 10
it's not efficient by any means, but it's equivalent to what you have, just shorter.
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
add a comment |
How about turning it into a loop?
def classify(value):
i = -5
while i < 95:
if value < (i + 10) / 100.0 and value >= i / 100.0:
return '\' + repr((i + 5) / 100.0)
i += 10
it's not efficient by any means, but it's equivalent to what you have, just shorter.
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
add a comment |
How about turning it into a loop?
def classify(value):
i = -5
while i < 95:
if value < (i + 10) / 100.0 and value >= i / 100.0:
return '\' + repr((i + 5) / 100.0)
i += 10
it's not efficient by any means, but it's equivalent to what you have, just shorter.
How about turning it into a loop?
def classify(value):
i = -5
while i < 95:
if value < (i + 10) / 100.0 and value >= i / 100.0:
return '\' + repr((i + 5) / 100.0)
i += 10
it's not efficient by any means, but it's equivalent to what you have, just shorter.
answered 11 hours ago
MehrdadMehrdad
129k90415758
129k90415758
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
add a comment |
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
You need to start at ` i = -95`, though.
– Eric Duminil
5 hours ago
add a comment |
from decimal import Decimal
def classify(value):
number = Decimal(value)
result = "%.2f" % (number)
return Decimal(round(float(result), 2))
3
star imports are bad practice.
– bruno desthuilliers
10 hours ago
add a comment |
from decimal import Decimal
def classify(value):
number = Decimal(value)
result = "%.2f" % (number)
return Decimal(round(float(result), 2))
3
star imports are bad practice.
– bruno desthuilliers
10 hours ago
add a comment |
from decimal import Decimal
def classify(value):
number = Decimal(value)
result = "%.2f" % (number)
return Decimal(round(float(result), 2))
from decimal import Decimal
def classify(value):
number = Decimal(value)
result = "%.2f" % (number)
return Decimal(round(float(result), 2))
edited 4 hours ago
wizzwizz4
3,60011637
3,60011637
answered 12 hours ago
Asif AkhtarAsif Akhtar
78110
78110
3
star imports are bad practice.
– bruno desthuilliers
10 hours ago
add a comment |
3
star imports are bad practice.
– bruno desthuilliers
10 hours ago
3
3
star imports are bad practice.
– bruno desthuilliers
10 hours ago
star imports are bad practice.
– bruno desthuilliers
10 hours ago
add a comment |
You don't need the and value >= -.85
in elif value < -0.75 and value >= -0.85:
; if the value isn't greater than or equal to -.85, then you won't reach the elif. You can also just turn all the elif
s into if
by having each one return immediately.
In this case, since you have the boundaries at regular intervals, you can just round (in the general case of regular intervals, you may have to divide and then round, for instance if the intervals are at every three units, then you would divide the number by three and round). In the general case, it's faster to store the boundaries in a tree structure, and then do a binary search for where the item goes.
Doing a binary search explicitly would be something like this:
def classify(value):
if value < -.05:
if value < -.45:
if value < -.65:
if value < -.85:
if value < -.95:
return None
return r'-0.9'
if value < -.75:
return r'-0.8'
return r'-0.7'
...
Although this code is harder to read than yours, it runs in time logarithmic rather than linear with respect to the number of boundaries.
If the number of items is significantly larger than the number of boundaries, it would probably be faster to actually create a tree of the items, and insert the boundaries.
You could also create a list, sort it, and then look at the index. For instance, compare (sorted([(_-9.5)/10 for _ in range(20)]+[x]).index(x)-9)/10
to your function.
add a comment |
You don't need the and value >= -.85
in elif value < -0.75 and value >= -0.85:
; if the value isn't greater than or equal to -.85, then you won't reach the elif. You can also just turn all the elif
s into if
by having each one return immediately.
In this case, since you have the boundaries at regular intervals, you can just round (in the general case of regular intervals, you may have to divide and then round, for instance if the intervals are at every three units, then you would divide the number by three and round). In the general case, it's faster to store the boundaries in a tree structure, and then do a binary search for where the item goes.
Doing a binary search explicitly would be something like this:
def classify(value):
if value < -.05:
if value < -.45:
if value < -.65:
if value < -.85:
if value < -.95:
return None
return r'-0.9'
if value < -.75:
return r'-0.8'
return r'-0.7'
...
Although this code is harder to read than yours, it runs in time logarithmic rather than linear with respect to the number of boundaries.
If the number of items is significantly larger than the number of boundaries, it would probably be faster to actually create a tree of the items, and insert the boundaries.
You could also create a list, sort it, and then look at the index. For instance, compare (sorted([(_-9.5)/10 for _ in range(20)]+[x]).index(x)-9)/10
to your function.
add a comment |
You don't need the and value >= -.85
in elif value < -0.75 and value >= -0.85:
; if the value isn't greater than or equal to -.85, then you won't reach the elif. You can also just turn all the elif
s into if
by having each one return immediately.
In this case, since you have the boundaries at regular intervals, you can just round (in the general case of regular intervals, you may have to divide and then round, for instance if the intervals are at every three units, then you would divide the number by three and round). In the general case, it's faster to store the boundaries in a tree structure, and then do a binary search for where the item goes.
Doing a binary search explicitly would be something like this:
def classify(value):
if value < -.05:
if value < -.45:
if value < -.65:
if value < -.85:
if value < -.95:
return None
return r'-0.9'
if value < -.75:
return r'-0.8'
return r'-0.7'
...
Although this code is harder to read than yours, it runs in time logarithmic rather than linear with respect to the number of boundaries.
If the number of items is significantly larger than the number of boundaries, it would probably be faster to actually create a tree of the items, and insert the boundaries.
You could also create a list, sort it, and then look at the index. For instance, compare (sorted([(_-9.5)/10 for _ in range(20)]+[x]).index(x)-9)/10
to your function.
You don't need the and value >= -.85
in elif value < -0.75 and value >= -0.85:
; if the value isn't greater than or equal to -.85, then you won't reach the elif. You can also just turn all the elif
s into if
by having each one return immediately.
In this case, since you have the boundaries at regular intervals, you can just round (in the general case of regular intervals, you may have to divide and then round, for instance if the intervals are at every three units, then you would divide the number by three and round). In the general case, it's faster to store the boundaries in a tree structure, and then do a binary search for where the item goes.
Doing a binary search explicitly would be something like this:
def classify(value):
if value < -.05:
if value < -.45:
if value < -.65:
if value < -.85:
if value < -.95:
return None
return r'-0.9'
if value < -.75:
return r'-0.8'
return r'-0.7'
...
Although this code is harder to read than yours, it runs in time logarithmic rather than linear with respect to the number of boundaries.
If the number of items is significantly larger than the number of boundaries, it would probably be faster to actually create a tree of the items, and insert the boundaries.
You could also create a list, sort it, and then look at the index. For instance, compare (sorted([(_-9.5)/10 for _ in range(20)]+[x]).index(x)-9)/10
to your function.
answered 6 hours ago
AcccumulationAcccumulation
1,42329
1,42329
add a comment |
add a comment |
Try something like this, if you don't like loops:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_folder = [ r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
idx = [value >= end for end in endpts].index(False)
if not idx:
raise ValueError('Value outside of range')
return ts_folder[idx-1]
Of course, the loop is just "hidden" in the list comprehension.
Obviously, in this example, it would be better to generate endpts
and ts_fol
programmatically rather than writing them all out, but you indicated that in the real situation the endpoints and values aren't so straightforward.
This raises a ValueError
if value
≥ 0.95 (because False
is not found in the list comprehension) or if value
< -0.95 (because then idx
is 0); the original version raises a UnboundLocalError
in these cases.
You could also save three lines and skip a few comparisons by doing this:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_fol = [ None, r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
return next((ts for ts, end in zip(ts_fol, endpts) if value < end), None)
This version returns None
rather than raising exceptions for any value outside the bounds.
add a comment |
Try something like this, if you don't like loops:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_folder = [ r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
idx = [value >= end for end in endpts].index(False)
if not idx:
raise ValueError('Value outside of range')
return ts_folder[idx-1]
Of course, the loop is just "hidden" in the list comprehension.
Obviously, in this example, it would be better to generate endpts
and ts_fol
programmatically rather than writing them all out, but you indicated that in the real situation the endpoints and values aren't so straightforward.
This raises a ValueError
if value
≥ 0.95 (because False
is not found in the list comprehension) or if value
< -0.95 (because then idx
is 0); the original version raises a UnboundLocalError
in these cases.
You could also save three lines and skip a few comparisons by doing this:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_fol = [ None, r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
return next((ts for ts, end in zip(ts_fol, endpts) if value < end), None)
This version returns None
rather than raising exceptions for any value outside the bounds.
add a comment |
Try something like this, if you don't like loops:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_folder = [ r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
idx = [value >= end for end in endpts].index(False)
if not idx:
raise ValueError('Value outside of range')
return ts_folder[idx-1]
Of course, the loop is just "hidden" in the list comprehension.
Obviously, in this example, it would be better to generate endpts
and ts_fol
programmatically rather than writing them all out, but you indicated that in the real situation the endpoints and values aren't so straightforward.
This raises a ValueError
if value
≥ 0.95 (because False
is not found in the list comprehension) or if value
< -0.95 (because then idx
is 0); the original version raises a UnboundLocalError
in these cases.
You could also save three lines and skip a few comparisons by doing this:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_fol = [ None, r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
return next((ts for ts, end in zip(ts_fol, endpts) if value < end), None)
This version returns None
rather than raising exceptions for any value outside the bounds.
Try something like this, if you don't like loops:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_folder = [ r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
idx = [value >= end for end in endpts].index(False)
if not idx:
raise ValueError('Value outside of range')
return ts_folder[idx-1]
Of course, the loop is just "hidden" in the list comprehension.
Obviously, in this example, it would be better to generate endpts
and ts_fol
programmatically rather than writing them all out, but you indicated that in the real situation the endpoints and values aren't so straightforward.
This raises a ValueError
if value
≥ 0.95 (because False
is not found in the list comprehension) or if value
< -0.95 (because then idx
is 0); the original version raises a UnboundLocalError
in these cases.
You could also save three lines and skip a few comparisons by doing this:
def classify(value):
endpts = [-0.95, -0.85, -0.75, -0.65, -0.55, -0.45, -0.35, -0.25, -0.15, -0.05, 0.05, 0.15, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 0.85, 0.95]
ts_fol = [ None, r'-0.9', r'-0.8', r'-0.7', r'-0.6', r'-0.5', r'-0.4', r'-0.3', r'-0.2', r'-0.1', r'.0', r'.1', r'.2', r'.3', r'.4', r'.5', r'.6', r'.7', r'.8', r'.9']
return next((ts for ts, end in zip(ts_fol, endpts) if value < end), None)
This version returns None
rather than raising exceptions for any value outside the bounds.
edited 1 hour ago
answered 2 hours ago
KundorKundor
2,9661325
2,9661325
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55180829%2fpython-if-else-code-style-for-reduced-code-for-rounding-floats%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
44
That is the longest code for a rounding function I've ever seen!
– Aran-Fey
12 hours ago
I agree with @Aran-Fey. That thing's huge, OP!
– connectyourcharger
12 hours ago
That's an example. In my experiment, diffence isn't always 0.5. round() is a good way in this case but not always work for me
– Kuang 鄺世銘
12 hours ago
6
At the very least, use chained comparisons:
-0.95 <= value < -0.85
instead of `value < -0.85 and value >= -0.95– chepner
11 hours ago
2
It's a great way to hide bugs!
ts_folder
is undefined for values larger than0.95
or smaller than-0.85
. Also, the result for-0.45
and-0.35
differ by0.2
.– Eric Duminil
6 hours ago