2016-05-04 9 views
1

この関数は、数字とターゲット整数の文字列を取り、オペレータを挿入して目的のターゲットに到達するすべての可能な方法を出力します。すべての場合、出力にはすべての桁が順番に含まれていなければなりません。何も省略することができる。この関数を任意の長さの文字列にする

#!/usr/bin/env python3 

def find_expressions(digits, target): 
    if not (isinstance(digits, str) or isinstance(digits, list)) or not isinstance(target, int): 
     raise TypeError 
    if len(digits) != 5: 
     raise TypeError('digits must be of length 5') 
    solutions = [] 
    operators = ('', ' + ', ' - ', ' * ', '/') 
    for i in operators: 
     for j in operators: 
      for k in operators: 
       for l in operators: 
        s = digits[0] + i + digits[1] + j + digits[2] + k + digits[3] + l + digits[4] 
        try: 
         if eval(s) == target: 
          solutions.append(s + ' == {}'.format(target)) 
        except (ZeroDivisionError, SyntaxError): 
         pass 
    print('\n'.join(solutions)) 

きれいではありませんが、動作します。問題は、長さが5の文字列しか必要としないということです。どのようにすれば、それを任意の長さの文字列にすることができますか? (たとえば、find_expressions('12345678', 2)を呼び出すことは有効です。)私はforループを再帰で置き換える必要があると考えていますが、これを達成する方法については迷っています。

出力例

呼び出すfind_expressions('75228', 5)プリント:

7 + 5 + 2/2 - 8 == 5 
7 * 5 - 22 - 8 == 5 
7 * 5 - 2 - 28 == 5 

警告は

私は、私はすべての可能性を超えるループすることによって取って全体の強引なアプローチに満足していませんよ。もっと良いアルゴリズムがあれば、それについて聞きたいと思います。 しかし、この質問は、可能な限り小さな変更をしながら任意の長さの入力を行うことに関するものです。

+3

あなたは 'itertools'モジュールを調べましたか? – TigerhawkT3

+0

はい、私は持っていますが、動作するようなものは見ませんでした。私は何かを見落としている可能性が高いですが、私の人生のために、それが何であるかを理解することはできません。 –

+0

ここでは、2桁の数字は、例の出力に表示されていますか? – martineau

答えて

5

使用itertools.product

import itertools 

def find_expressions(digits, target): 
    if not (isinstance(digits, str) or isinstance(digits, list)) or not isinstance(target, int): 
     raise TypeError 

    solutions = [] 
    operators = ('', ' + ', ' - ', ' * ', '/') 
    for ops in itertools.product(operators, repeat=len(digits)-1): 
     s = digits[0] + ''.join(op + digit for op, digit in zip(ops, digits[1:])) 
     try: 
      if eval(s) == target: 
       solutions.append(s + ' == {}'.format(target)) 
     except (ZeroDivisionError, SyntaxError): 
      pass 
    print('\n'.join(solutions)) 
+0

私はそれを明確にするために質問を編集しました。このアプローチでは、forループの機能を複製するのではなく、ペアを生成するだけです。上に追加した入力例では、 '7 - 2 == 5 'が得られます。これは、入力のすべての数字が含まれていないため無効です。 –

+0

@ScottSeverance私はtargetとの比較を追加し、あなたのテストケースとまったく同じ結果を出力することを確認しました。失敗した別のテストケースを提供できますか? [私はideoneで同じ結果を得る](http://ideone.com/7swBjk)。 – phihag

+0

あなたの編集したバージョンはうまくいくように私に見えます。その間、私はitertools.productを自分で演奏し、自分の記事の最初のバージョンのアイデアに自分のソリューションベースを思いついた。ありがとう。 –

1

トリックはすべて可能な順列シーケンス+-*/得ることです - 重複を含むが、その最初のシーケンスは++++する必要があります。 nの数字の場合は、n - 1の演算子が必要です。その長さはlen(digits)-1である必要があります。

順列の総数はoperators ** positionsです。つまり、すべてのオペレータがすべての単一の位置に表示されます。私は実際にはない便利なショートカットが表示されませんすべての可能性をテストします。

次は、大まかにGet all 4-character combinations of a given alphabetに基づいています。数字の入力を行わずに# print ..行を有効にすると、リスト全体が表示されます。

入力が文字列である場合とそうでない場合は、str(digits[x])を使用して文字列連結がbarfにならないようにしてください。

次のコード

def find_expressions(digits, target): 
    if not (isinstance(digits, str) or isinstance(digits, list)) or not isinstance(target, int): 
     raise TypeError 
    solutions = [] 
    operators = ('', ' + ', ' - ', ' * ', '/') 
    used = [0] * (len(digits)-1) 
    for i in range(len(operators)**(len(digits)-1)): 
     attempt = str(digits[0]) 
     for j in range(1,len(digits)): 
     attempt += operators[used[j-1]] + str(digits[j]) 
     # print (operators[used[j-1]], end="") 
     # print() 
     for j in range(len(digits)-1): 
     used[j] += 1 
     if used[j] >= len(operators): 
      used[j] = 0 
     else: 
      break 

     try: 
     if eval(attempt) == target: 
      print (attempt, '==', eval(attempt)) 
     except (ZeroDivisionError, SyntaxError): 
     pass 

find_expressions ([7,5,2,2,8], 5) 

は(floatとしてここで最後のプリント/はそれを行うため)

7 * 5 - 2 - 28 == 5 
7 * 5 - 22 - 8 == 5 
7 + 5 + 2/2 - 8 == 5.0 

を示しています。

関連する問題