views:

419

answers:

3

Faulty code:

pos_1 = 234
pos_n = 12890
min_width = len(str(pos_n)) # is there a better way for this?

# How can I use min_width as the minimal width of the two conversion specifiers?
# I don't understand the Python documentation on this :(
raw_str = '... from %(pos1)0*d to %(posn)0*d ...' % {'pos1':pos_1, 'posn': pos_n}

Required output:

... from 00234 to 12890 ...

           ______________________EDIT______________________

New code:

# I changed my code according the second answer
pos_1 = 10234 # can be any value between 1 and pos_n
pos_n = 12890
min_width = len(str(pos_n))

raw_str = '... from % *d to % *d ...' % (min_width, pos_1, min_width, pos_n)

New Problem:

There is one extra whitespace (I marked it *_*) in front of the integer values, for intigers with *min_width* digits:

print raw_str
... from _10234 to _12890 ...

Also, I wonder if there is a way to add Mapping keys?

+2  A: 
"1234".rjust(13,"0")

Should do what you need

addition:

a = ["123", "12"]    
max_width = sorted([len(i) for i in a])[-1]

put max_width instead of 13 above and put all your strings in a single array a (which seems to me much more usable than having a stack of variables).

additional nastyness: (Using array of numbers to get closer to your question.)

a = [123, 33, 0 ,223]
[str(x).rjust(sorted([len(str(i)) for i in a])[-1],"0") for x in a]

Who said Perl is the only language to easily produce braindumps in? If regexps are the godfather of complex code, then list comprehension is the godmother.

(I am relatively new to python and rather convinced that there must be a max-function on arrays somewhere, which would reduce above complexity. .... OK, checked, there is. Pity, have to reduce the example.)

[str(x).rjust(max([len(str(i) for i in a]),"0") for x in a]

And please observe below comments on "not putting calculation of an invariant (the max value) inside the outer list comprehension".

Don Johe
Thanks, I am going to use your suggestion concerning the array.Regarding *rjust*: Currently, I need to understand the *%* operator for string formatting, that's why I am bound to it. Sorry, should have mentioned that.
SimonSalman
You really would want to break the max() calculation out and capture it in a variable before doing the .rjust() list. Otherwise you'll be re-calculating the inner list and max() value for **every** item in the outer list! (But your general remark about list comprehensions is nice :)
ThomasH
+3  A: 
pos_1 = 234
pos_n = 12890
min_width = len(str(pos_n))

raw_str = '... from %0*d to %0*d ...' % (min_width, pos_1, min_width, pos_n)
Amber
imho, you don't need to pad second number - it already has minimum width
Mihail
True, although if the code were ever modified to take the longer of the two numbers (which might be necessary if pos_1 could be negative and thus require an extra character for the negation) it'd be safer to pass both widths.
Amber
Thanks, so far! I just run into new trouble after changing the filling character from *0* to *whitespace*. I would be glad if you could have a look on my new example.
SimonSalman
For filling with whitespace, just use %*d - don't actually put a space between the % and the * or else it will indeed bug out.
Amber
Thanks a lot :)
SimonSalman
The *% \*d* idiom is interesting if you mix positive and negative numbers, and want them to align nicely, so Python leaves a blank before positives, and '-' in front of negatives, both consuming the same space.
ThomasH
+1  A: 

Concerning using a mapping type as second argument to '%':

I presume you mean something like that '%(mykey)d' % {'mykey': 3}, right?! I think you cannot use this if you use the "%*d" syntax, since there is no way to provide the necessary width arguments with a dict.

But why don't you generate your format string dynamically:

fmt = '... from %%%dd to %%%dd ...' % (min_width, min_width)
# assuming min_width is e.g. 7 fmt would be: '... from %7d to %7d ...'
raw_string = fmt % pos_values_as_tuple_or_dict

This way you decouple the width issue from the formatting of the actual values, and you can use a tuple or a dict for the latter, as it suits you.

ThomasH
dunno if I can +1 that. It is funny though, but isn't that driving "sticking to the %-operator" a little to far into unreadability? It's somehow cool 'though, if probably not advisable.
Don Johe
You can always break up the final output string in smaller, more manageable pieces, treat them individually (either with '%' or .rjust or whatever works), and the compose the final string from these substrings. Then something like *widthfmt="%d" % min_width; fieldfmt="%" + widthfmt + "d"* looks less daunting.
ThomasH