2017-06-05 8 views
3

私はitertoolsを使用して数学演算子を反復しようとしています。 通常とarray私は結果を得ることができcombinationsを使用して[1, 2, 3]、の:Pythonの静的でexcecutableな数式を渡って算術演算子を反復する方法は?

1 
1,2 
1,3 
2,3 
1,2,3 

などを

私は、このような方法で[1, 2, 3]arrayでこれを使用すること:

1+2+3 
1+2-3 
1+2/3 
1+2*3 
1-2+3 
1-2-3 
1-2/3 
1-2*3 
... 

が発生し、式の結果が得られます。

これを行うにはどうすればよいですか?ここで

+3

を[オペレータ](https://docs.python.orgにおける標準算術演算を実行する機能があります/3/library/operator.html)モジュール。 –

+2

2つの方法が考えられます:一つはあなたの数式を文字列として作り、それを評価するために 'eval'を使います。もう1つは、 'operator'モジュールから関数を使用することです。 –

+0

'int'の' __add__'、 '__sub__'、' __mul__'と '__div__'メソッドを見てください。 –

答えて

1

オペランドの任意の数に一般化溶液、および演算子の通常の優先順位保存:

from itertools import product 

operands = [1, 2, 3, 4] 
operators = [ '+', '*', '-', '//' ] # change '//' to '/' for floating point division 
for opers in product(operators, repeat=len(operands)-1): 
    formula = [ str(operands[0]) ] 
    for op, operand in zip(opers, operands[1:]): 
     formula.extend([op, str(operand)]) 
    formula = ' '.join(formula) 
    print('{} = {}'.format(formula, eval(formula))) 
+0

これは本当に良いです。しかし、 '//'を '/'に変更すると、 '//'と同じ答えになります。だから、部門はややオフです。 –

+0

Erm、Python 2.xを使用しますか?この例では、これを追加しない限り、 '/'と '//'の間に違いはありません: 'from __future__ import division' –

+0

それを修正しました。 –

1

は、私はそれにアプローチする方法を次のとおりです。

import itertools 
import operator 

まず、すべての可能な組み合わせのリストを作る:

funcs = [operator.add, operator.sub, operator.mul, operator.div] 

combos = list(itertools.product(funcs, repeat=2)) 

>>[(<function operator.add>, <function operator.add>), 
(<function operator.add>, <function operator.sub>), 
(<function operator.add>, <function operator.mul>), 
(<function operator.add>, <function operator.div>), 
(<function operator.sub>, <function operator.add>), 
(<function operator.sub>, <function operator.sub>), 
(<function operator.sub>, <function operator.mul>), 
(<function operator.sub>, <function operator.div>), 
(<function operator.mul>, <function operator.add>), 
(<function operator.mul>, <function operator.sub>), 
(<function operator.mul>, <function operator.mul>), 
(<function operator.mul>, <function operator.div>), 
(<function operator.div>, <function operator.add>), 
(<function operator.div>, <function operator.sub>), 
(<function operator.div>, <function operator.mul>), 
(<function operator.div>, <function operator.div>)] 

その後、我々はすべての可能な結果解決このリストを反復処理します:

for fn in combos: 
    print 'This combo {} yielded this result {}'.format(fn, fn[1](fn[0](*seq[:2]), seq[-1])) 

This combo (<built-in function add>, <built-in function add>) yielded this result 6 
This combo (<built-in function add>, <built-in function sub>) yielded this result 0 
This combo (<built-in function add>, <built-in function mul>) yielded this result 9 
This combo (<built-in function add>, <built-in function div>) yielded this result 1 
This combo (<built-in function sub>, <built-in function add>) yielded this result 2 
This combo (<built-in function sub>, <built-in function sub>) yielded this result -4 
This combo (<built-in function sub>, <built-in function mul>) yielded this result -3 
This combo (<built-in function sub>, <built-in function div>) yielded this result -1 
This combo (<built-in function mul>, <built-in function add>) yielded this result 5 
This combo (<built-in function mul>, <built-in function sub>) yielded this result -1 
This combo (<built-in function mul>, <built-in function mul>) yielded this result 6 
This combo (<built-in function mul>, <built-in function div>) yielded this result 0 
This combo (<built-in function div>, <built-in function add>) yielded this result 3 
This combo (<built-in function div>, <built-in function sub>) yielded this result -3 
This combo (<built-in function div>, <built-in function mul>) yielded this result 0 
This combo (<built-in function div>, <built-in function div>) yielded this result 0 

編集:これは操作の規則に従う方法です

ops = ['+','-','*','/'] 

combos = list(itertools.product(ops, repeat=2)) 

for tup in list(itertools.product(combos, [seq])): 
    print 'These operations {} evaluate to this ---> {}'.format(tup[0],eval(''.join(*zip(seq[0],tup[0][0],seq[1],tup[0][1],seq[-1])))) 

These operations ('+', '+') evaluate to this ---> 6 
These operations ('+', '-') evaluate to this ---> 0 
These operations ('+', '*') evaluate to this ---> 7 
These operations ('+', '/') evaluate to this ---> 1 
These operations ('-', '+') evaluate to this ---> 2 
These operations ('-', '-') evaluate to this ---> -4 
These operations ('-', '*') evaluate to this ---> -5 
These operations ('-', '/') evaluate to this ---> 1 
These operations ('*', '+') evaluate to this ---> 5 
These operations ('*', '-') evaluate to this ---> -1 
These operations ('*', '*') evaluate to this ---> 6 
These operations ('*', '/') evaluate to this ---> 0 
These operations ('/', '+') evaluate to this ---> 3 
These operations ('/', '-') evaluate to this ---> -3 
These operations ('/', '*') evaluate to this ---> 0 
These operations ('/', '/') evaluate to this ---> 0 
+2

これは、このコンボ(<組み込み関数sub>、<組み込み関数mul>)がこの結果-3をもたらしたことを意味します。1 - 2 * 3 === 1-6 == -3? :)操作の優先順位についてはどうですか? –

+1

[bodmasルール](https://en.wikipedia.org/wiki/Order_of_operations)を尊重しません。 1 + 2 * 3は9にならないはずです。 –

+0

はい、そうです。私は操作の順序を考慮しませんでした.1秒間修正します –

0

operatorモジュールの対応する関数を使用して、それらのペアを反復処理します。今

import itertools 
import operator 

ops = [operator.add, operator.sub, operator.mul, operator.div] 

for f1, f2 in itertools.product(*ops, repeat=2): 
    print f1(array[0], f2(array[1], array[2])) 

arrayは、任意の長さを持つことができるならば、それはビットのトリッカーを取得します。

for operations in itertools.product(*ops, repeat=len(array)-1): 
    result = operations[0](array[0], array[1]) 
    for op, operand in zip(operations[1:], array[2:]): 
     result = op(result, operand) 
    print(result) 

上記の構造は、各操作に適切な識別要素を知る必要がなくなります。

優先度に従いたい場合は、式を作成してeval(標準の警告が適用されます)と評価する必要があります。

for ops in itertool.product("+", "-", "*", "/", repeat=len(array)-1): 
    expr = "%s%s%s" % (array[0], ops[0], array[1]) 
    for op, operand in zip(ops[1:], array[2:]): 
    expr = "%s%s%s" % (expr, op, operand) 
    result = eval(expr) 

私は1+2*3に加えて(1+2)*3のような括弧で囲まれた表現を生成するために、これを拡大する練習としてそれを残します。

+0

'len(array)'を 'len(array)-1'に置き換えました - 演算子の数は1つのオペランドの数よりも小さいです。 –

+0

ありがとうございます。 'zip'への呼び出しで' operations'と 'array'が異なる開始インデックスでスライスされて何かが私を何か間違ったものにしましたが、私は何を考えるのか止まらなかったのです。 – chepner

+0

これらを実行しようとしましたが、それは言う: TypeError: 'int'オブジェクトは反復可能ではありません 私はそれが2を指していると思います。 –

1

私の論理を指摘するためにエレガントなもの(膝の上に作られていませんが)は機能しませんが、機能します。 リストを正しい順序で1つずつ減らすことです。例えば。:

データ:1 * 2 + 3 * 4

  • ステップ1(第*評価)後:2 + 3 * 4
  • ステップ2(第2 *評価)後:2 + 12
  • ステップ3の後
  • (+評価):14

コード:

import operator 
import itertools 

data = [1.0, 2.0, 3.0, 4.0] 
operators_1 = [operator.mul, operator.div] # this operators have priority over that below 
operators_2 = [operator.add, operator.sub] 

def processOps(formula, data, operators): 
    res_formula = list(formula) 
    result = list(data) 
    for op in formula: 
     if op not in operators: continue 

     i = res_formula.index(op) 
     result = result[:i] + [op(result[i], result[i + 1])] + result[i + 2:] 
     res_formula.remove(op) 

     if len(result) == 1: 
      break 

    return (res_formula, result) 

for f in itertools.product(operators_1 + operators_2, repeat=len(data)-1): 
    result = list(data) 
    formula = list(f) 
    formula, result = processOps(formula, result, operators_1) 
    formula, result = processOps(formula, result, operators_2) 
    print f, result 

UDPこの更新されたロジックは、(1 * 2)+(3/4)のようなケースを正しく処理します。

+0

ここでいくつか間違いがあります。以下の場合: (<組み込み関数div>、<組み込み関数mul>、<組み込み関数add>)[4.166666666666667] ここで1/2 * 3 + 4でなければなりません。答えは5.5 –

+0

私はあなたの次の編集を見ました、これは素晴らしい作品です。ありがとうございました:) –

+0

@ NameyMcNamo、ありがとう、この質問のために - それは私がそれを働かせて本当に面白かった –

関連する問題