I'm not sure what you mean by "restarting the loop." In this particular case, it seems to me that you just need to re-apply the function to the expression until it is reduced to a value. This is less effective than it could be, but it works and is understandable. So that...
def find_op(tokens, oplist): for i, token in enumerate(tokens): if token in oplist: return i else: return -1 def reduce_binary_infix(tokens, i, ops): op = ops[tokens[i]] tokens[i - 1: i + 2] = [op(tokens[i - 1], tokens[i + 1])] return tokens def evaluate(tokens, ops, precedence): for prec in precedence: index = find_op(tokens, prec) while index >= 0: tokens = reduce_binary_infix(tokens, index, ops) index = find_op(tokens, prec) return tokens print evaluate([2, '+', 3, '+', 4, '+', 5], ops, precedence)
Tested:
>>> print evaluate([2, '+', 3, '+', 4, '+', 5], ops, precedence) [14]
This can be made more efficient without repeating the whole chain. This can be done using the start_index parameter in find_op and by reduce_binary_infix return the new current index along with the reduced list.
It is also a little more verbose than what you have, but I think it helps the readability of the code - not to mention its reuse.