By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
 426,115 Members | 898 Online
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 426,115 IT Pros & Developers. It's quick & easy.

# "number-in-base" ``oneliner''

 P: n/a I hesitate a bit to post this, but... on the Italian Python NG, somebody was asking whether there was any way to convert an integer number x into a string which represents it in an arbitrary base N (given a sequence with a len of N that gives the digits to use) as "a single expression". I haven't found a really general way, much less a clear one, but, the best I have so far is...: def number_in_base(x, N, digits, maxlen=99): return '-'[x>=0:] + ( (x and ''.join([digits[k%N] for i in range(maxlen) for k in [abs(x)//N**i] if k>0])[::-1] ) or digits[0]) Besides the lack of clarity, the obvious defect of this approach is that darned 'maxlen' parameter -- but then, since I can have only a 'for', not a 'while', in a list comprehension or generator expression, and I don't think recursion qualifies as 'a single expression'...:-( Anyway, improvements and suggestions welcome, thanks! Alex Jul 18 '05 #1
Share this Question
21 Replies

 P: n/a On Fri, 29 Oct 2004 23:58:47 +0200, al*****@yahoo.com (Alex Martelli) wrote: I hesitate a bit to post this, but... on the Italian Python NG, somebodywas asking whether there was any way to convert an integer number x intoa string which represents it in an arbitrary base N (given a sequencewith a len of N that gives the digits to use) as "a single expression".I haven't found a really general way, much less a clear one, but, thebest I have so far is...:def number_in_base(x, N, digits, maxlen=99): return '-'[x>=0:] + ( (x and ''.join([digits[k%N] for i in range(maxlen) for k in [abs(x)//N**i] if k>0])[::-1] ) or digits[0])Besides the lack of clarity, the obvious defect of this approach is thatdarned 'maxlen' parameter -- but then, since I can have only a 'for',not a 'while', in a list comprehension or generator expression, and Idon't think recursion qualifies as 'a single expression'...:-(Anyway, improvements and suggestions welcome, thanks! Maybe something useful in this? Not very tested (and not terribly clear either ;-) def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in iter( ... lambda qr=[abs(x),0]:qr[0] and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]) ... , 0)][::-1]) ... number_in_base( 126 ,2,'0123456789ABCDEF') '1111110' number_in_base( 126 ,8,'0123456789ABCDEF') '176' number_in_base( 126 ,16,'0123456789ABCDEF') '7E' number_in_base( 1 ,16,'0123456789ABCDEF') '1' number_in_base( 0 ,16,'0123456789ABCDEF') '0' number_in_base(-126 ,16,'0123456789ABCDEF') '-7E' number_in_base(-126 ,2,'0123456789ABCDEF') '-1111110' Even less tested, and using a list subtype with overridden next to do the same: def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in type('',(list,),{ ... '__iter__':lambda s:s, 'next':lambda s:( ... s[0] is 0 and iter([]).next() or ... s.__setslice__(0,2,divmod(s[0],N)) or digits[s[1]]) ... })([abs(x),0])][::-1]) ... number_in_base(-126, 8, '01234567') '-176' number_in_base(-126, 2, '01') '-1111110' number_in_base(126, 2, '01') '1111110' number_in_base( 0 , 2, '01') '0' number_in_base( 1 , 2, '01') '1' ;-) Regards, Bengt Richter Jul 18 '05 #2

 P: n/a On Fri, 29 Oct 2004 23:58:47 +0200, al*****@yahoo.com (Alex Martelli) wrote: I hesitate a bit to post this, but... on the Italian Python NG, somebodywas asking whether there was any way to convert an integer number x intoa string which represents it in an arbitrary base N (given a sequencewith a len of N that gives the digits to use) as "a single expression".I haven't found a really general way, much less a clear one, but, thebest I have so far is...:def number_in_base(x, N, digits, maxlen=99): return '-'[x>=0:] + ( (x and ''.join([digits[k%N] for i in range(maxlen) for k in [abs(x)//N**i] if k>0])[::-1] ) or digits[0])Besides the lack of clarity, the obvious defect of this approach is thatdarned 'maxlen' parameter -- but then, since I can have only a 'for',not a 'while', in a list comprehension or generator expression, and Idon't think recursion qualifies as 'a single expression'...:-(Anyway, improvements and suggestions welcome, thanks! Maybe something useful in this? Not very tested (and not terribly clear either ;-) def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in iter( ... lambda qr=[abs(x),0]:qr[0] and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]) ... , 0)][::-1]) ... number_in_base( 126 ,2,'0123456789ABCDEF') '1111110' number_in_base( 126 ,8,'0123456789ABCDEF') '176' number_in_base( 126 ,16,'0123456789ABCDEF') '7E' number_in_base( 1 ,16,'0123456789ABCDEF') '1' number_in_base( 0 ,16,'0123456789ABCDEF') '0' number_in_base(-126 ,16,'0123456789ABCDEF') '-7E' number_in_base(-126 ,2,'0123456789ABCDEF') '-1111110' Even less tested, and using a list subtype with overridden next to do the same: def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in type('',(list,),{ ... '__iter__':lambda s:s, 'next':lambda s:( ... s[0] is 0 and iter([]).next() or ... s.__setslice__(0,2,divmod(s[0],N)) or digits[s[1]]) ... })([abs(x),0])][::-1]) ... number_in_base(-126, 8, '01234567') '-176' number_in_base(-126, 2, '01') '-1111110' number_in_base(126, 2, '01') '1111110' number_in_base( 0 , 2, '01') '0' number_in_base( 1 , 2, '01') '1' ;-) Regards, Bengt Richter Jul 18 '05 #3

 P: n/a On Sat, 30 Oct 2004 06:07:23 GMT, bo**@oz.net (Bengt Richter) wrote: [...]Maybe something useful in this? Not very tested (and not terribly clear either ;-) def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in iter( ... lambda qr=[abs(x),0]:qr[0] and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]) ... , 0)][::-1]) ... Alternatively, a little more compactly (though I feel guilty about the -1 ;-): def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0] + ''.join(list(iter(lambda qr=[abs(x),-1]: (qr[0] or qr[1]<0) and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]), False))[::-1]) ... number_in_base(126,2,'01') '1111110' number_in_base( 126, 8,'01234567') '176' number_in_base(-126, 8,'01234567') '-176' number_in_base( -1, 2,'01234567') '-1' number_in_base( 1, 2,'01234567') '1' number_in_base( 0, 2,'01234567') '0' Regards, Bengt Richter Jul 18 '05 #4

 P: n/a wrote: ... def number_in_base(x, N, digits, maxlen=99): return '-'[x>=0:] + ( (x and ''.join([digits[k%N] for i in range(maxlen) for k in [abs(x)//N**i] if k>0])[::-1] ) or digits[0]) ... range(maxlen) can be replaced with range(int(math.log(x) / math.log(N)) + 1). Right! I had missed that because I was focusing on builtin names only. Thanks! Also, and perhaps you are already aware, number_in_base(x, 1, '0') Yes, I was aware that the pre condition N>=2 (as well as other preconditions, such as len(digits) >= N) are not checked; sorry for not making that clear. doesn't produce the correct output with the above algorithm, although I believe it will if you switch to using math.log(). With math.log it raises a ZeroDivisionError -- arguably more correct than a bunch of 0's, yes. It's interesting that the math.log application does catch such errors as N<2;-). Alex Jul 18 '05 #5

 P: n/a On Sat, 30 Oct 2004 07:48:34 GMT, bo**@oz.net (Bengt Richter) wrote: On Sat, 30 Oct 2004 06:07:23 GMT, bo**@oz.net (Bengt Richter) wrote:[...]Maybe something useful in this? Not very tested (and not terribly clear either ;-) >>> def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in iter( ... lambda qr=[abs(x),0]:qr[0] and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]) ... , 0)][::-1]) ...Alternatively, a little more compactly (though I feel guilty about the -1 ;-): def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0] + ''.join(list(iter(lambda qr=[abs(x),-1]: (qr[0] or qr[1]<0) and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]), False))[::-1]) ... Yet another, prefixing digits instead of joining reversed list: def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0]+reduce(lambda s,c:c+s, iter(lambda qr=[abs(x),-1]: (qr[0] or qr[1]<0) ... and (qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]), False)) ... number_in_base( 0 , 2, '01') '0' number_in_base( 1 , 2, '01') '1' number_in_base(126, 2, '01') '1111110' number_in_base(-126, 2, '01') '-1111110' Regards, Bengt Richter Jul 18 '05 #6

 P: n/a On Fri, 29 Oct 2004 23:34:42 GMT, ex*****@divmod.com wrote: range(maxlen) can be replaced with range(int(math.log(x) / math.log(N)) + 1). Log accepts the base as second argument. def number_in_base(x, N=10, digits="0123456789ABCDEF"): return '-'[x>=0:]+"".join( [digits[abs(x)/N**i%N] for i in xrange(1+int(math.log(abs(x)+1,N))) if N**i<=abs(x)][::-1]) or digits[0] Also, and perhaps you are already aware, number_in_base(x, 1, '0') doesn't produce the correct output with the above algorithm, although I believe it will if you switch to using math.log(). It doesn't handle roman numerals either... but so ? You can't count using base 1 with positional systems. Andrea Jul 18 '05 #7

 P: n/a On Sat, 30 Oct 2004 12:12:36 +0000, Andrea Griffini wrote: You can't count using base 1 with positional systems. Well, you can, sort of. You end up with the integers, obviously, and the result has a rather striking resemblance to the modern foundations of number theory, in which there is only one number, 0, and the "increment" function which returns a number one larger. If you want three, it is expressed increment(increment(increment(0))), which is rather similar to the base-1 number "111". Zero in this system would probably be a null string, making increment this: def increment(number): return "1" + number (And abracadabra, I'm back on topic for the newsgroup, albeit tenuously :-) ) Some people say base 2 is the most natural base in the universe. But you can certainly make a claim for base 1, based on its correspondence to number theory, from which we build the rest of math. (Most people never dig this deep; it was one of my favorite classes in Comp. Sci., though, and we're probably the only people other than mathematicians to offer the course.) Jul 18 '05 #8

 P: n/a Hi all, warning: off topic nitpicking below! Jeremy Bowers said unto the world upon 2004-10-30 13:29: On Sat, 30 Oct 2004 12:12:36 +0000, Andrea Griffini wrote:You can't count using base 1 with positional systems. Well, you can, sort of. You end up with the integers, obviously, and the result has a rather striking resemblance to the modern foundations of number theory, in which there is only one number, 0, and the "increment" function which returns a number one larger. If you want three, it is expressed increment(increment(increment(0))), which is rather similar to the base-1 number "111". I take it you didn't mean 0 was the only number, but rather the only primitive number. (Alternatively " '0' is the only individual constant" in the cant I prefer.) I am also surprised to see "increment" -- I come to that material with working in Philosophy of Mathematics and Logic, but almost every presentation I have ever seen uses "successor". (I'm going off of philosophical and mathematical logic presentations.) I do so wish that terminology is the whole area would just stabilize already! Zero in this system would probably be a null string, making increment this: def increment(number): return "1" + number (And abracadabra, I'm back on topic for the newsgroup, albeit tenuously :-) ) Some people say base 2 is the most natural base in the universe. But you can certainly make a claim for base 1, based on its correspondence to number theory, from which we build the rest of math. (Most people never dig this deep; it was one of my favorite classes in Comp. Sci., though, and we're probably the only people other than mathematicians to offer the course.) I've never taken a single comp. sci. course, so I will both claim and commit disciplinary bias: serious undergrad logic/foundations of maths courses do happen in Philosophy, too :-) On the other hand, I'm a bit surprised that these things get taught in comp. sci. This past summer when teaching Intro to Logic, I encountered at least one fourth-year comp. sci. student who had no idea what an axiomatic system was :-| print "We now return you to your usual programing" Best to all, Brian vdB Jul 18 '05 #9

 P: n/a On Sat, 30 Oct 2004 16:06:04 -0400, Brian van den Broek wrote: I take it you didn't mean 0 was the only number, but rather the only primitive number. (Alternatively " '0' is the only individual constant" in the cant I prefer.) *shrug* Can't say I get worked up over the difference there. Regardless, you "can't" write "3". (Of course you can define it, but that's true of everything.) I am also surprised to see "increment" -- I come to that material with working in Philosophy of Mathematics and Logic, but almost every presentation I have ever seen uses "successor". (I'm going off of philosophical and mathematical logic presentations.) Yeah, that would be right. Couldn't recall the exact name. number theory, from which we build the rest of math. (Most people never dig this deep; it was one of my favorite classes in Comp. Sci., though, and we're probably the only people other than mathematicians to offer the course.) I've never taken a single comp. sci. course, so I will both claim and commit disciplinary bias: serious undergrad logic/foundations of maths courses do happen in Philosophy, too :-) Gonna nit pick myself here: "Most people". I think adding Philosophers and dilettantes and the rare electrical engineer isn't likely to change the "most". On the other hand, I'm a bit surprised that these things get taught in comp. sci. This past summer when teaching Intro to Logic, I encountered at least one fourth-year comp. sci. student who had no idea what an axiomatic system was :-| Graduate level. And many of the grads hated it. There is a chasm between the average Comp. Sci. student and the average professor; it isn't so bad at the grad level but it is still there. I'm not sure if it's worse than most disciplines, but I am inclined to believe it is, since Comp Sci typically can't really work out if it is math or engineering (wide consensus is that while there are scientific aspects to it, it probably shouldn't have it in the name), and there are, in my experience, fairly clean divisions of each student and professor into one camp or another. I was one of the exceedingly rare students who could do both quite well, and freely translate between them. Jul 18 '05 #10

 P: n/a On Sat, 30 Oct 2004 09:02:14 GMT, bo**@oz.net (Bengt Richter) wrote: On Sat, 30 Oct 2004 07:48:34 GMT, bo**@oz.net (Bengt Richter) wrote:On Sat, 30 Oct 2004 06:07:23 GMT, bo**@oz.net (Bengt Richter) wrote:[...]Maybe something useful in this? Not very tested (and not terribly clear either ;-) >>> def number_in_base(x, N, digits): ... return x==0 and digits[0] or '-'[:x<0] + ''.join([d for d in iter( ... lambda qr=[abs(x),0]:qr[0] and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]) ... , 0)][::-1]) ...Alternatively, a little more compactly (though I feel guilty about the -1 ;-): >>> def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0] + ''.join(list(iter(lambda qr=[abs(x),-1]: (qr[0] or qr[1]<0) and ( ... qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]), False))[::-1]) ...Yet another, prefixing digits instead of joining reversed list: def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0]+reduce(lambda s,c:c+s, iter(lambda qr=[abs(x),-1]: (qr[0] or qr[1]<0) ... and (qr.__setslice__(0,2,divmod(qr[0],N)) or digits[qr[1]]), False)) ... My best shot so far (unless I goofed ;-): def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0]+''.join([digits[r] for x in [[abs(x)]] ... for x[0],r in iter(lambda:divmod(x[0], N), (0,0))][::-1]) or '0' ... number_in_base( 126, 2) '1111110' number_in_base(-126, 2) '-1111110' number_in_base(-126, 8) '-176' number_in_base(-126,16) '-7E' number_in_base( 1,16) '1' number_in_base( 1, 2) '1' number_in_base( 0, 2) '0' Regards, Bengt Richter Jul 18 '05 #11

 P: n/a On Sat, 30 Oct 2004 09:02:14 GMT, bo**@oz.net (Bengt Richter) wrote: [... previous versions ...] Silly last best shot put the quotient in an unneeded box. Sorry for all the self-followups. I think I'll call this my best version (so far ;-): def number_in_base(x, N=10, digits='0123456789ABCDEF'): ... return '-'[:x<0]+''.join([digits[r] for q in [abs(x)] ... for q,r in iter(lambda:divmod(q, N), (0,0))][::-1]) or '0' ... number_in_base( 126, 2) '1111110' number_in_base(-126, 2) '-1111110' number_in_base(-126, 8) '-176' number_in_base(-126,16) '-7E' number_in_base( 1,16) '1' number_in_base( 1, 2) '1' number_in_base( 0, 2) '0' Regards, Bengt Richter Jul 18 '05 #12

 P: n/a On Sun, 31 Oct 2004 03:11:07 GMT, bo**@oz.net (Bengt Richter) wrote: [...] Goofed ;-/ def number_in_base(x, N=10, digits='0123456789ABCDEF'): return '-'[:x<0]+''.join([digits[r] for q in [abs(x)] for q,r in iter(lambda:divmod(q, N), (0,0))][::-1]) or digits[0] (Shouldn't have hardwired '0' in place of digits[0]) It must be time to eat ... sorry. Regards, Bengt Richter Jul 18 '05 #13

 P: n/a On Sat, 30 Oct 2004 16:06:04 -0400, Brian van den Broek wrote: Hi all,warning: off topic nitpicking below!Jeremy Bowers said unto the world upon 2004-10-30 13:29: On Sat, 30 Oct 2004 12:12:36 +0000, Andrea Griffini wrote:You can't count using base 1 with positional systems. Well, you can, sort of. You end up with the integers, obviously, and the result has a rather striking resemblance to the modern foundations of number theory, in which there is only one number, 0, and the "increment" function which returns a number one larger. If you want three, it is expressed increment(increment(increment(0))), which is rather similar to the base-1 number "111".I take it you didn't mean 0 was the only number, but rather the onlyprimitive number. (Alternatively " '0' is the only individual constant"in the cant I prefer.)I am also surprised to see "increment" -- I come to that material withworking in Philosophy of Mathematics and Logic, but almost everypresentation I have ever seen uses "successor". (I'm going off ofphilosophical and mathematical logic presentations.) Also the representation used in that context is normally "0,s0,ss0" or a similar one; anyway using TWO symbols. In math, or anywhere you need precision, it's important to weight the words; I said "positional" and normally the unary counting method is not considered "positional". There are a lot of methods for representing numbers, both historically used (roman, for example) or just theorically possible. When the word "base" is used the assumption is a positional system; and 1 cannot be used as base in a positional system. More to the point the objection that the code that Alex wrote didn't handle "unary" counting is IMO quite pointless as that counting system is not more related to the positional than the ancient roman counting system. Of course anyone can give the the words whatever meaning, it just gets harder to communicate. Also, if ones really wants to support another different number representation system after a generic positional I would prefer the roman one, that's still used nowdays. Andrea -- "When I use a word," Humpty Dumpty said, in rather a scornful tone, "it means just what I choose it to mean—neither more nor less." Jul 18 '05 #14

 P: n/a On Fri, 29 Oct 2004 23:58:47 +0200, al*****@yahoo.com (Alex Martelli) wrote: I hesitate a bit to post this, but... on the Italian Python NG, somebodywas asking whether there was any way to convert an integer number x intoa string which represents it in an arbitrary base N (given a sequencewith a len of N that gives the digits to use) as "a single expression".I haven't found a really general way, much less a clear one, but, thebest I have so far is...:def number_in_base(x, N, digits, maxlen=99): return '-'[x>=0:] + ( (x and ''.join([digits[k%N] for i in range(maxlen) for k in [abs(x)//N**i] if k>0])[::-1] ) or digits[0])Besides the lack of clarity, the obvious defect of this approach is thatdarned 'maxlen' parameter -- but then, since I can have only a 'for',not a 'while', in a list comprehension or generator expression, and Idon't think recursion qualifies as 'a single expression'...:-(Anyway, improvements and suggestions welcome, thanks! Not sure if I got filtered out replying to myself, what with an accidental dupe and all the incremental changes and corrections ;-/ Anyway, I guess you could say there's a "while" implicit in iter(f, sentinel) that you _can_ do within a list comprehension ;-) To sum up, my final version (hope it doesn't still have a bug ;-) was: def number_in_base(x, N=10, digits='0123456789ABCDEF'): return '-'[:x<0]+''.join([digits[r] for q in [abs(x)] for q,r in iter(lambda:divmod(q, N), (0,0))][::-1]) or digits[0] BTW, will anything that works in a list comprehension work in a generator expression (assuming one does not depend on the generator expression having leftover outside side effect bindings like the LC version)? Regards, Bengt Richter Jul 18 '05 #15

 P: n/a Bengt Richter wrote: Not sure if I got filtered out replying to myself, what with an accidental dupe and all the incremental changes and corrections ;-/ Anyway, I guess you could say there's a "while" implicit in iter(f, sentinel) that you _can_ do within a list comprehension ;-) Yep, excellent suggestion, tx. I went with the logarithm suggestion, but in other cases the two-arguments iter could surely be the best way to hide a 'while callable() != sentinel:' in a list comprehension!-) Alex Jul 18 '05 #16

 P: n/a Andrea Griffini wrote in message news:. .. On Fri, 29 Oct 2004 23:34:42 GMT, ex*****@divmod.com wrote: range(maxlen) can be replaced with range(int(math.log(x) / math.log(N)) + 1). Log accepts the base as second argument. def number_in_base(x, N=10, digits="0123456789ABCDEF"): return '-'[x>=0:]+"".join( [digits[abs(x)/N**i%N] for i in xrange(1+int(math.log(abs(x)+1,N))) if N**i<=abs(x)][::-1]) or digits[0] Also, and perhaps you are already aware, number_in_base(x, 1, '0') doesn't produce the correct output with the above algorithm, although I believe it will if you switch to using math.log(). It doesn't handle roman numerals either... That's easy enough to implement ;-) roman = lambda n: 'M' * (n // 1000) + ('', 'C', 'C', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM')[n // 100 % 10] + ('', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC')[n // 10 % 10] + ('', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX')[n % 10] I'm sure there's a shorter way, though. Jul 18 '05 #17

 P: n/a Bengt Richter oz.net> writes: BTW, will anything that works in a list comprehension work in a generator expression (assuming one does not depend on the generator expression having leftover outside side effect bindings like the LC version)? Well, I'm not confident enough to say *anything* (though I've used them freely in my code since 2.4a1 was released and have never had any problems) but they seem to work for this problem: def number_in_base(n, b=10, digits='0123456789ABCDEF'): .... return '-'[:n<0]+''.join(reversed(list( .... digits[r] .... for q in [abs(n)] .... for q, r in iter(lambda: divmod(q, b), (0, 0))))) or digits[0] .... number_in_base(100, 16) '64' number_in_base(100, 2) '1100100' Of course, you don't really gain anything by doing this with a generator expression since you have to reverse the list. In Python 3000, the list(genexp) syntax will be exactly equivalent to a list comprehension[1], at which point, it won't matter. ;) Steve [1] http://www.python.org/peps/pep-3000.html#core-language Jul 18 '05 #18

 P: n/a On 31 Oct 2004 21:12:49 -0800, da*****@yahoo.com (Dan Bishop) wrote: roman = lambda n: 'M' * (n // 1000) + ('', 'C', 'C', 'CCC', 'CD', 'D','DC', 'DCC', 'DCCC', 'CM')[n // 100 % 10] + ('', 'X', 'XX', 'XXX','XL', 'L', 'LX', 'LXX', 'LXXX', 'XC')[n // 10 % 10] + ('', 'I', 'II','III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX')[n % 10]I'm sure there's a shorter way, though. This is a bit shorter ... roman = lambda x: "".join(["".join(map(lambda c: "IVXLCDM"[ord(c) - ord("A")+2*N], "/A/AA/AAA/AB/B/BA/BAA/BAAA/AC".split("/")[x//10**N % 10])) for N in (3, 2, 1, 0)]) Andrea Jul 18 '05 #19

 P: n/a On Mon, 01 Nov 2004 07:21:09 GMT, Andrea Griffini wrote: This is a bit shorter ...roman = lambda x: "".join(["".join(map(lambda c: "IVXLCDM"[ord(c) -ord("A")+2*N], "/A/AA/AAA/AB/B/BA/BAA/BAAA/AC".split("/")[x//10**N %10])) for N in (3, 2, 1, 0)]) No idea why I initially thougt about using ASCII codes... this is simpler and shorter... roman = lambda x: "".join(["".join(map(lambda c: "IVXLCDM"[int(c) +2*N],"/0/00/000/01/1/10/100/1000/02".split("/")[x//10**N % 10])) for N in (3, 2, 1, 0)]) Andrea Jul 18 '05 #20

 P: n/a Andrea Griffini wrote: roman = lambda x: "".join(["".join(map(lambda c: "IVXLCDM"[int(c) +2*N],"/0/00/000/01/1/10/100/1000/02".split("/")[x//10**N % 10])) for N in (3, 2, 1, 0)]) This rocks!! I'm still trying to understand how it works though :) --Irmen Jul 18 '05 #21

 P: n/a On Mon, 01 Nov 2004 11:06:24 +0100, Irmen de Jong wrote: Andrea Griffini wrote: roman = lambda x: "".join(["".join(map(lambda c: "IVXLCDM"[int(c) +2*N],"/0/00/000/01/1/10/100/1000/02".split("/")[x//10**N % 10])) for N in (3, 2, 1, 0)])This rocks!! I'm still trying to understand how it works though :) The idea is to use the pattern "", "0", "00", "000", "01", "1", "10", "100", "1000", "02" where every character listed above is an offest in "IVX", "XLC", "CDM", "M??" For example applying the offsets to the first group you get: "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" i.e. the roman numbers for 0..9; and applying it to the second "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", i.e. 0, 10, 20, ... 90. I just used "split" and string indexing instead of regular lists because the code becomes smaller (and more readable than a mess of quotes and commas). The rest is a loop on the thousands, the hundreds, the tens and the units of the number and the joins needed to glue all the pieces into a resulting string. Andrea Jul 18 '05 #22

### This discussion thread is closed

Replies have been disabled for this discussion.