188

7
+4  Q:

## [Python] How can I improve this code?

``````# max_list = [83, 1350, 1, 100]
for i in range(len(max_list)):
new_value = 1
while new_value < max_list[i]:
new_value *= 10
max_list = new_value
``````

What I'm doing is rounding numbers up to the closest, uhm, zero filled value? I'm not sure what it would be called. But basically, I want 83 -> 100, 1 -> 1, 1350 -> 10000, 100 -> 100. I tried using the round() function but couldn't get it to do what I wanted.

This does it but I thought it could be written in less lines.

+3  A:
``````def nextPowerOfTen(x):
if x in [0, 1]:
return x
elif x < 1:
return -nextPowerOfTen(abs(x))
else:
return 10**len(str(int(x) - 1))

>>> nextPowerOfTen(83)
100
>>> nextPowerOfTen(1350)
10000
>>> nextPowerOfTen(1)
1
>>> nextPowerOfTen(100)
100
>>> nextPowerOfTen(0)
0
>>> nextPowerOfTen(-1)
-1
>>> nextPowerOfTen(-2)
-10
``````

It does something sensible with negatives, not sure if that is the behaviour you want or not.

Fails on powers of 10.
Fixed failure on powers of 10
+1  A:

i need it to be 1350 / 10000 = 0.135 so it's in the [0, 1] range.

Why didn't you say so initially?

``````new_val = float("0." + str(old_val))
``````

Unless you need the numbers for something else as well?

you probably want to use float(), not int()
i'm using floating points too - i forgot to mention it - so i think i'd have to remove the separator. but that looks like it'll work
Doesn't this fail for 1, `1->0.1` should be `1->1`?
@Bwmat: Fixed, thanks. @Stephen: Yes, it does. However, [0, 1] is actually kind of a funny range to use - [0, 1) is generally more useful. I'd be interested in seeing how @iceburn intends to use these "normalized" values.
@Anon i'll use them with a neural network
+1  A:
``````>>> x = 12345.678
>>> y = round(x)
>>> round(10 * y, -len(str(y)))
100000
``````
doesn't work for floating points though. i forgot to mention that sorry
Edited and Fixed.
A:

Pseudocode:

``````div = input != 1 ? power(10,truncate(log10(abs(input))) + 1) : 1;
percent = input/div;
``````
+11  A:

I'd do it mathematically:

``````from math import ceil, log10
int(pow(10, ceil(log10(abs(x or 0.1)))))
``````
I'd use `pow(10, ceil(abs(log10(x))))` for the case of negative input.
+1, Look at you, bringing intelligence where everyone else brought string processing :) And zero is a trivial special case.
.. and don't forget to import `*` (or at least `pow`, `ceil` and `log10`) from `math` ;)
`int(pow(10, ceil(log10(abs(x) or 0.1))))` would work better for x < 1
@Stephen: str() version is actually a hair (7-8%) faster than the log10() one
A:

Your original code was close, and more easily read than some terse expression. The problem with your code is a couple of minor errors: initializing `new_value` each time in the initial scan, rather than only once; and replacing the `max_list` with a calculated scalar while looping over it as a list.

On the final line, you must have intended:

``````    max_list[i] = float(max_list[i]) / new_value
``````

but you dropped the array index, which would replace the list with a single value. On the second iteration of the loop, your Python would give an exception due to the invalid index into a non-list.

Because your code develops greater and greater values of new_value as it progresses, I recommend you not replace the list items during the first scan. Make a second scan once you calculate a final value for new_value:

``````max_list = [83, 1350, 1, 100]

# Calculate the required "normalizing" power-of-ten
new_value = 1.0
for i in range(len(max_list)):
while new_value < max_list[i]:
new_value *= 10.0

# Convert the values to fractions in [0.0, 1.0]
for i in range(len(max_list)):
max_list[i] = max_list[i] / new_value

print max_list
# "[0.0083000000000000001, 0.13500000000000001, 0.0001, 0.01]"
``````

Notice that I was required to initialize new_value as if it were a floating-point value, in order that it would result in floating-point quotients. There are alternative ways to do this, such as using `float(max_list[i])` to retrieve the value for normalizing. The original calculation of `new_value` was starting over with each element, so your example would return `new_value == 100` because this was based off the final element in the input list, which is 100.

max_list has the maximum of each column in a file. after changing the values i then divide each element for its respective maximum, eg if the first line in my file is: 10, 10, 20, 30 and my maximums are 10, 100, 100, 1000 i'll have 1, 0.1, 0.2, 0.03 as the new first line. the code i posted only shows one part of what i'm doing, which is taking the maximums and rounding them
In that case, the only thing wrong with your original code is the "final line" comment I made. :)
A:
``````from math import ceil, log10

# works for floats, too.
x = [83, 1350, 1, 100, 12.75]
y = [10**ceil(log10(el)) for el in x]

# alt list-comprehension if integers needed
# y = [int(10**ceil(log10(el))) for el in x]
``````