Why Python don't accept 03 as a number?

jfong at ms4.hinet.net jfong at ms4.hinet.net
Sat Dec 8 21:55:56 EST 2018


Avi Gross於 2018年12月9日星期日 UTC+8上午1時40分26秒寫道:
> Jach,
> 
> Just for fun, I looked at the  puzzle you asked about and solved it several
> ways without running into your 03 problem at all. There are more efficient
> solutions than total brute force.
> 
> Anyone not interested, stop here, please. After my explanations, I show a
> python program then the output it produces.
> 
> The comments in the python program (below) explain the solution classes but
> let me suggest a little algebra simplifies the problem so fewer brute force
> iterations are needed.
> 
> The simplistic algorithm can be written as a single list comprehension with
> (in this case) 5 "for" clauses and one "if" clause.
> 
> You are solving for: ab + aa + cd == ce
> 
> So 
> for all digits possible for a
> for all remaining digits possible for b each iteration
> for all remaining digits possible for c each iteration
> for all remaining digits possible for d each iteration
> for all remaining digits possible for e each iteration
> if the condition applies.
> 
> Clearly the above is deeply nested with 10!/5! Iterations or 30,240.
> 
> But a little algebra simplifies the solution so c drops out of the equation
> as shown below in the comments.
> The test becomes:  21*a + b + d - e == 0
> 
> You can apply that as the condition using four loops. You get 32 solutions
> and for each you can let c be any of 10 possibilities for 320 total
> solutions, if I did it right. The number of iterations is now only 5,040 and
> you are evaluating fewer terms with c gone. The full test would have been
> (10*a +b )+ (10*a + a) + (10*c + d) == (10*c + e)
> 
> BUT a tad more analysis shows that all solutions require "a" to be zero. If
> a >=1 then 21*a must be >= 21.
> But b and c cannot be more than 9+8 which is 17 and subtracting e makes it
> no larger. So "a" MUST be zero.
> 
> So the solution can be done with only three loops for b, d, and e. 720
> iterations.
> 
> The commented code is below. It can be done in as little as two lines of
> code if the list comprehension is done in one line but why make it hard to
> read.
> 
> If there is a flaw in my reasoning or the program below, please point it
> out. You said there were 192 solutions. I found 320.
> And, there are more efficient solutions possible but overkill for this
> application.
> 
> Avi
> 
> ################### START CODE ##############
> # GOAL: find all solutions of a puzzle
> # ab + aa + cd == ce
> # Where each of the letters a through e
> # are UNIQUE values ranging from 0 to 9
> 
> # Make the equation simpler
> # expand ab to 10*a + b
> # expand aa to 10*a + a
> # expand cd to 10*c + d
> # add to get 21*a + b + 10*c + d
> # expand ce to 10*c + e
> # simplify 21*a + b + 10*c + d = 10*c + e
> # the 10*c on both sides cancel.
> # RESULT: 21*a + b + d - e = 0
> # the value of c is not relevant and
> # you can solve without e and then add back
> # all ten possibilities later.
> 
> # Method:
> # Use a set of digits.
> # Use a list comprehension with four loops.
> # Each loop chooses all available values
> # for a,b,d,e by subtracting the set
> # of digits already in use at the time from all digits.
> 
> digits = set(range(10))
> 
> matches = [ (a, b, d, e)
>             for a in digits
>             for b in (digits - {a})
>             for d in (digits -{a,b})
>             for e in (digits -{a,b,d})
>             if ( 21*a + b + d - e == 0)
>             ]
> 
> print("SOLVING FOR: 21*a + b + d - e == 0")
> print(f"matches found in batches of 10: {len(matches)}")
> 
> for (a,b,d,e) in matches:
>     solution =  {'a' : a,
>                     'b' : b,
>                     'c' : 'any digit',
>                     'd' : d,
>                     'e' : e
>                  }
>     print(solution)
> 
> # Note the result shows all solutions have 'a' being zero.
> # That was obvious from the equation as there were 21 of them
> # and if a was 1 in 21*a + b + d - e = 0
> # then clearly band d cannot be more than 9+8 so no solution
> # unless a == 0.
> # So you can solve this easier using the above techique by just
> # solving b + d - e = 0
> 
> matches = [ (b, d, e)
>             for b in digits
>             for d in (digits -{b})
>             for e in (digits -{b,d})
>             if ( b + d == e)
>             ]
> 
> print("\nSOLVING FOR: b + d == e")
> print(f"matches found in batches of 10: {len(matches)}")
> 
> for (b,d,e) in matches:
>     solution =  {'a' : '0',
>                     'b' : b,
>                     'c' : 'any digit',
>                     'd' : d,
>                     'e' : e
>                  }
>     print(solution)
> 
> ################### END CODE ##############
> ################### BEGIN OUTPUT ##############
> SOLVING FOR: 21*a + b + d - e == 0
> matches found in batches of 10: 32
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 2, 'e': 3}
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 3, 'e': 4}
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 4, 'e': 5}
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 5, 'e': 6}
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 6, 'e': 7}
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 7, 'e': 8}
> {'a': 0, 'b': 1, 'c': 'any digit', 'd': 8, 'e': 9}
> {'a': 0, 'b': 2, 'c': 'any digit', 'd': 1, 'e': 3}
> {'a': 0, 'b': 2, 'c': 'any digit', 'd': 3, 'e': 5}
> {'a': 0, 'b': 2, 'c': 'any digit', 'd': 4, 'e': 6}
> {'a': 0, 'b': 2, 'c': 'any digit', 'd': 5, 'e': 7}
> {'a': 0, 'b': 2, 'c': 'any digit', 'd': 6, 'e': 8}
> {'a': 0, 'b': 2, 'c': 'any digit', 'd': 7, 'e': 9}
> {'a': 0, 'b': 3, 'c': 'any digit', 'd': 1, 'e': 4}
> {'a': 0, 'b': 3, 'c': 'any digit', 'd': 2, 'e': 5}
> {'a': 0, 'b': 3, 'c': 'any digit', 'd': 4, 'e': 7}
> {'a': 0, 'b': 3, 'c': 'any digit', 'd': 5, 'e': 8}
> {'a': 0, 'b': 3, 'c': 'any digit', 'd': 6, 'e': 9}
> {'a': 0, 'b': 4, 'c': 'any digit', 'd': 1, 'e': 5}
> {'a': 0, 'b': 4, 'c': 'any digit', 'd': 2, 'e': 6}
> {'a': 0, 'b': 4, 'c': 'any digit', 'd': 3, 'e': 7}
> {'a': 0, 'b': 4, 'c': 'any digit', 'd': 5, 'e': 9}
> {'a': 0, 'b': 5, 'c': 'any digit', 'd': 1, 'e': 6}
> {'a': 0, 'b': 5, 'c': 'any digit', 'd': 2, 'e': 7}
> {'a': 0, 'b': 5, 'c': 'any digit', 'd': 3, 'e': 8}
> {'a': 0, 'b': 5, 'c': 'any digit', 'd': 4, 'e': 9}
> {'a': 0, 'b': 6, 'c': 'any digit', 'd': 1, 'e': 7}
> {'a': 0, 'b': 6, 'c': 'any digit', 'd': 2, 'e': 8}
> {'a': 0, 'b': 6, 'c': 'any digit', 'd': 3, 'e': 9}
> {'a': 0, 'b': 7, 'c': 'any digit', 'd': 1, 'e': 8}
> {'a': 0, 'b': 7, 'c': 'any digit', 'd': 2, 'e': 9}
> {'a': 0, 'b': 8, 'c': 'any digit', 'd': 1, 'e': 9}
> 
> SOLVING FOR: b + d == e
> matches found in batches of 10: 32
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 2, 'e': 3}
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 3, 'e': 4}
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 4, 'e': 5}
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 5, 'e': 6}
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 6, 'e': 7}
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 7, 'e': 8}
> {'a': '0', 'b': 1, 'c': 'any digit', 'd': 8, 'e': 9}
> {'a': '0', 'b': 2, 'c': 'any digit', 'd': 1, 'e': 3}
> {'a': '0', 'b': 2, 'c': 'any digit', 'd': 3, 'e': 5}
> {'a': '0', 'b': 2, 'c': 'any digit', 'd': 4, 'e': 6}
> {'a': '0', 'b': 2, 'c': 'any digit', 'd': 5, 'e': 7}
> {'a': '0', 'b': 2, 'c': 'any digit', 'd': 6, 'e': 8}
> {'a': '0', 'b': 2, 'c': 'any digit', 'd': 7, 'e': 9}
> {'a': '0', 'b': 3, 'c': 'any digit', 'd': 1, 'e': 4}
> {'a': '0', 'b': 3, 'c': 'any digit', 'd': 2, 'e': 5}
> {'a': '0', 'b': 3, 'c': 'any digit', 'd': 4, 'e': 7}
> {'a': '0', 'b': 3, 'c': 'any digit', 'd': 5, 'e': 8}
> {'a': '0', 'b': 3, 'c': 'any digit', 'd': 6, 'e': 9}
> {'a': '0', 'b': 4, 'c': 'any digit', 'd': 1, 'e': 5}
> {'a': '0', 'b': 4, 'c': 'any digit', 'd': 2, 'e': 6}
> {'a': '0', 'b': 4, 'c': 'any digit', 'd': 3, 'e': 7}
> {'a': '0', 'b': 4, 'c': 'any digit', 'd': 5, 'e': 9}
> {'a': '0', 'b': 5, 'c': 'any digit', 'd': 1, 'e': 6}
> {'a': '0', 'b': 5, 'c': 'any digit', 'd': 2, 'e': 7}
> {'a': '0', 'b': 5, 'c': 'any digit', 'd': 3, 'e': 8}
> {'a': '0', 'b': 5, 'c': 'any digit', 'd': 4, 'e': 9}
> {'a': '0', 'b': 6, 'c': 'any digit', 'd': 1, 'e': 7}
> {'a': '0', 'b': 6, 'c': 'any digit', 'd': 2, 'e': 8}
> {'a': '0', 'b': 6, 'c': 'any digit', 'd': 3, 'e': 9}
> {'a': '0', 'b': 7, 'c': 'any digit', 'd': 1, 'e': 8}
> {'a': '0', 'b': 7, 'c': 'any digit', 'd': 2, 'e': 9}
> {'a': '0', 'b': 8, 'c': 'any digit', 'd': 1, 'e': 9}
> ################### END OUTPUT ##############
> 
> -----Original Message-----
> From: Python-list <python-list-bounces+avigross=verizon.net at python.org> On
> Behalf Of jfong at ms4.hinet.net
> Sent: Saturday, December 8, 2018 4:26 AM
> To: python-list at python.org
> Subject: Re: Why Python don't accept 03 as a number?
> 
> Avi Gross at 2018/12/8 UTC+8 PM2:09:20 wrote:
> > [[READERS DIGEST CONDENSED ANSWER: use int("string") ]]
> > 
> > Since we all agree python will not make notations like "05" work 
> > indefinitely, and the need expressed is how to solve a symbolic puzzle 
> > (see message below) then it makes sense to look at alternate
> representations.
> > 
> > I have a question first. How are you solving your puzzles? 
> > 
> >     ab + aa + cd == ce
> 
> Try all the combinations:-)
> 
> The only way I can think of is try-error. It takes no more 10 lines to go
> from "ab + aa + cd == ce" to yield one correct answer, such as "03 + 00 + 15
> == 18", using itertools' permutations(), string's translate() and re.
> 
> > Why does 05 ever even appear in your solution?
> 
> I don't know. There is total 192 answers for this puzzle anyway.
> 
> > Are you generating all possible answers by setting each variable to 
> > one of 0 to 9 then the second to any of the remaining nine choices 
> > then the third to the remaining 8 and so on? For any method like that, 
> > you can presumably make each component like
> > 
> > ab = 10*a + b
> > 
> > in the loop.
> > 
> > Similarly for aa and cd and ce. If the equality above is true, you 
> > found the solution and break out. If there can be multiple solutions, 
> > note the solution and keep going. But note for the 5 variables above, 
> > you are testing
> > 10*9*8*7*6 combinations.
> > 
> > Another idea is to use strings like "05" as bizarrely, the function 
> > int() seems to be an ex eption that does NOT care about leading 
> > whitespace or
> > zeroes:
> > 
> > >>> int("05")
> > 5
> > >>> int("  0005")
> > 5
> > 
> > And even handles all zeroes:
> > 
> > >>> int("000000")
> > 0
> > 
> > You can also use lstrip() with an argument to remove zeros:
> > 
> > >>> a = eval("05".lstrip("0"))
> > 	     
> > >>> a
> > 	     
> > 5
> > 
> > If you are in a situation where you only want to remove leading zeroes 
> > if the following character is a digit and not "o" or "b" or "x", use 
> > regular expressions or other techniques.
> 
> As far as the leading zero problem was concerned, the simplest way is using
> re.sub()
> 
> > I will just toss in the possible use of the SymPy module to do actual 
> > symbolic computations to solve some of these. Perhaps a tad advanced.
> 
> I don't know SymPy and if it can shorten the execution time. But I am very
> curious about if there is other algorithm which can apply to this problem:-)
> 
> --Jach
> --
> https://mail.python.org/mailman/listinfo/python-list

I appreciate your analysis of this particular equation. Had learn something from it, especially the way the "matches" does. Thank you.

The actual equation is from the user input (sorry didn't mention it early) so can't do any analysis ahead, and also don't know how to write codes to do it too. The only way left to me is the "brute force" :-(

--Jach


More information about the Python-list mailing list