3

I know that "%03d" can do that pretty easily, but I'm trying to solve a slightly different problem. The part of my script, I need to find out how many numbers in a range (e.g. 0-999) have at lest one 3 (or any digit in question) in it. So, I came up with this lambda function:

fx = lambda z,y=999: [ "%03d" % (x, ) for x in range(y) if str(z) in str(x) ]

which is working great but I want to automate the padding 'leading zero' bit according to the range e.g. 003 when it's 999 or 09 for 88 and so on. Any idea how can I do that?

MacUsers
  • 2,091
  • 3
  • 35
  • 56
  • Is there a reason this is tagged `lambda` and `lambda-functions`? First, why is this a `lambda` instead of a `def` in the first place? And second, how does it matter either way to the question? – abarnert May 09 '13 at 22:48
  • The purpose of lambda is to do quick anonymous functions, once you assign it, it's no longer anonymous, and you're better off using the standard "def myfuc()". – monkut May 09 '13 at 22:54
  • @abarnert: My apology for lambda tag; removed now. – MacUsers May 09 '13 at 23:00
  • @MacUsers: As a side note, you get bonus points for doing `"%03d" % (x,)` instead of `"%03d" % x` (which the docs used to say not to use, but admit that it "works despite the ambiguity"… except of course in the cases where it doesn't work because of the ambiguity…). – abarnert May 09 '13 at 23:13

5 Answers5

6

If you want to pass a dynamic width to the formatting functions, you can:

>>> width = 5
>>> value = 2
>>> '%0*d' % (width, value)
'00002'

It's even easier with new-style formatting, because you can embed placeholders inside placeholders:

>>> width = 5
>>> value = 2
>>> '{1:0{0}}'.format(width, value)
'00002'

If you also want to know how to get the longest value in all of the values before outputting them, as long as you can iterate over the values twice, that's pretty easy:

>>> values = 3, 100, 50000
>>> width = max(len('%0d' % value) for value in values)
>>> ', '.join('%0*d' % (width, value) for value in values)
'00003, 00100, 50000'

And if you want to base it on a parameter, that's even easier:

fx = lambda z,y=999: [ "%0*d" % (len('%0d' % y), x) for x in range(y) if str(z) in str(x) ]

However, that's going to calculate the width of y over and over again, because inside an expression there's no easy way to store it, and a lambda can only take an expression.

Which raises the question of why you're using a lambda in the first place. The only advantage of lambda over def is that you can use it in an expression and don't need to come up with a name for it. If you're going to assign it to a name, that eliminates both advantages. So, just do this:

def fx(z, y=999):
    width = len('%0d' % y)
    return ["0%*d" % (width, x) for x in range(y) if str(z) in str(x)]
Alfe
  • 56,346
  • 20
  • 107
  • 159
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • Very helpful and also useful information; answer to my question as well. Thanks for the "new-style" formatting - keep forgetting about it. Only one issue, the output becomes a list of str in stead of int, hence no further calculation, like sum up the numbers etc. are possible. How can I output a list of integer in stead? Cheers!! – MacUsers May 09 '13 at 23:13
  • You can't return a list of 0-padded ints, because an _int_ can't be 0-padded. `0123` is the exact same number as `00123`, right? (And, to make it even more fun, they're the same as `83`, not `123`. See if you can guess why.) Only _strings_ can be 0-padded. `'0123'` is _not_ the same string as `'00123'`, right? – abarnert May 09 '13 at 23:16
  • Maybe what you want to do is split this up. First, return the list of numbers, with `[x for x in range(y) if str(z) in str(x)]`. Pass that around as numbers everywhere, but wherever you want to print them out, create the 0-padded strings from that list on the fly. Does that make sense? – abarnert May 09 '13 at 23:18
1

EDIT:

Just in case anyone new is looking at this, this is built into python

>>> x = 'some'
>>> print(x.zfill(10))
000000some

OLD ANSWER:

I had to do something similar with spaces to keep a log file lined up correctly

def format(z, rge = 999):
    lenRange = len(str(range(rge)[-1]))
    z = str(z)
    lenZ = len(z)
    if lenZ<lenRange:
        z = (lenRange - lenZ)*'0'+z #heres where yours and mine differed, i used " " instead of "0"
    return z
>>>format(1)
'001'
>>>format(12)
'012'
>>>format(123)
'123'

anything you put in this will be output with the same amount of chars... just dont put anything in there bigger than the biggest number in the range ( i guess since its a range.... you probably wont do that though)

edit....actually i think i misinterpreted the question.... ill leave this up in case it somehow manages to help someone else lol.

TehTris
  • 3,139
  • 1
  • 21
  • 33
1

I'm not sure it is appropriate (pythonic) or not.
Here is another solution with modern f-string.

num = 1
width = 5
out = f"{num:0{width}d}"

[0] Nested f-strings

Nothing
  • 13
  • 5
0

How about using `rjust' instead of formatting it?

fx = lambda z,y=999: [ str(x).rjust(len(str(y)), '0') for x in range(y) if str(z) in str(x) ]

That way, based on the width of y, you'll get the appropriate number of '0's:

>>> fx(3, 10)
['03']
>>> fx(3, 100)
['003', '013', '023', '030', '031', '032', '033', '034', '035', '036', '037', '038', '039', '043', '053', '063', '073', '083', '093']
Dan Lecocq
  • 3,383
  • 25
  • 22
0

How about this:

'%0*d' % (len(str(top)), i)
Alfe
  • 56,346
  • 20
  • 107
  • 159