Checking for unique output in Python

戏子无情 提交于 2019-12-23 17:23:17

问题


I came across a fun math problem yesterday and have it solved, but with the code I wrote, I had to do a keyboard interrupt or it would run forever, lol. So I changed it to have an end condition, but now it only prints 1 solution and stops.

The problem goes like this: "You have the numbers 123456789, in that order. Between each number, you must insert either nothing, a plus sign, or a multiplication sign, so that the resulting expression equals 2002. Write a program that prints all solutions. (There are two.)"

import random


def try1(param):
    global solved
    opers = ['+', '*', '']
    hotpotato = ('%s'.join(param) % (random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     )
             )
    if eval(hotpotato) == 2002:
        solved += 1
        print "Solution:", hotpotato, "= 2002     :-)"

    else:
        pass


solved = 0
while solved == 0:
    try1('123456789')

This code prints the first solution it encounters and stops. Can anyone tell me how to get it to print both solutions before it stops?


回答1:


Store your solutions in a set:

solutions = set([])

Each time a solution is found, update the set:

solutions.append(solution)

Sets are nice because there don't store duplicates:

>>> len(set([1, 1, 1, 1, 1, 1, 1]))
1

So just loop until the set's size is greater than one:

while len(solved) < 2:
    try1('123456789')

Also, you can shorten this code:

hotpotato = ('%s'.join(param) % (random.choice(opers),
                                 random.choice(opers),
                                 random.choice(opers),
                                 random.choice(opers),
                                 random.choice(opers),
                                 random.choice(opers),
                                 random.choice(opers),
                                 random.choice(opers),
                                 )
         )

To this:

hotpotato = ('%s'.join(param) % (random.choice(opers) for i in range(8))))



回答2:


Don't use random, enumerate all possible operator combinations (well, you can cut the search space a bit, if the first couple of numbers the result is larger than 2002, there is no way the result is going to be smaller). itertools is your friend.

If you do that, your program will finish in no time.

If you know that there are exactly two solutions you can return the solution from try1 and do the loop till you collected two different solutions, but that's not really elegant, is it?




回答3:


The solution to your problem is, breaking when solved == 2.

But your code's real problem is using random. Using random in an algorithm is generally a bad idea. There is a possibility that your code lasts over a century.

There is much simplier and faster way using itertools:

import itertools

for s in itertools.product(("+", "*", ""), repeat=8):
    z = itertools.izip_longest("123456789", s, fillvalue="")
    e = "".join(itertools.chain.from_iterable(z))

    if eval(e) == 2002:
        print(e)

There is no need to break when two solutions found, because the code already completes in 0.2 seconds :).




回答4:


To receive both (all) solutions you need completely different approach to solve this problem. Check all permutations of inserted operations. How to calculate permutations are shown here: http://www.bearcave.com/random_hacks/permute.html

EDIT:

Example:

ops = ['+', '*']

def gen(ver, i):
    if i == len(ver):
        return
    for op in ops:
        ver = ver[:i] + op + ver[i:]
        if eval(ver) == 2002:
            yield ver
        for j in range(i + 2, len(ver)):
            for sol in gen(ver, j):
                yield sol
        ver = ver[:i] + ver[i+1:]

for sol in gen("123456789", 1):
    print "solution:", sol

Output:

solution: 1*2+34*56+7+89
solution: 1*23+45*6*7+89



回答5:


For the record, I would encourage a different approach to search for the solutions, such as suggested in Andy T's answer or yi_H's answer. That said, this answer addresses the issue presented in the question.

The code you present will run until one answer is found and stop, since finding the first answer will make solved not equal 0. Since you know there are 2 solutions, you can change your while loop condition:

while solved < 2:
    try1('123456789')

In response to Mark's comment that this can lead to duplicated answers, here is code which will make sure you get different solutions:

import random
def try1(param):
    global solved
    try1.prev_soln = []
    opers = ['+', '*', '']
    hotpotato = ('%s'.join(param) % (random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     random.choice(opers),
                                     )
             )
    if eval(hotpotato) == 2002:
        if hotpotato not in try1.prev_soln:
            solved += 1
            try1.prev_soln.append(hotpotato)
            print "Solution:", hotpotato, "= 2002     :-)"    
    else:
        pass

solved = 0
while solved < 2:
    try1('123456789')

Of course, this approach assumes 2 solutions. If you had an unknown number of solutions you would not know when to stop, thus my recommendation for another approach to finding the solutions.



来源:https://stackoverflow.com/questions/7506264/checking-for-unique-output-in-python

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!