简体   繁体   中英

Creating a Python lambda function from a string sequence

I have a list of m elements and n different numbers that appear in a list of strings. The list follows the following format example

eq = ['12', '2', '3', '-123', '-1', 'X']

Note, X represents the constant 1, other than the variable 1. I want to be able to convert this to a lambda function that takes in a list x and acts like this list was summed together. For our example the function would be

f(x) = x[1]*x[2] + x[2] + x[3] - x[1]*x[2]*x[3] - x[1] + 1

I know how to do this with a normal function, but I wanted to get it to work with a lambda and hit a wall. Any help would be appreciated!

Here is the function that works for the problem:

def evaluateList(x, lst):
    num = 0
    for term in lst:
        if term[0] == "X":
            num += 1
        elif term[0] == "-":
            num -= reduce(lambda x,y: x*y, [x[int(y)-1] for y in term[1:]])
        else:
            num += reduce(lambda x,y: x*y, [x[int(y)-1] for y in term])
    return num

You can use functools.reduce twice, although the result is not very clean:

from functools import reduce
from operator import sub, add
eq = ['12', '2', '3', '-123', '-1', 'X']
_x = [6, 4, 1, 4, 5, 2, 4, 23, 2, 4]
final_result = reduce(lambda x, y:[add, sub][y.startswith('-')](
  reduce(lambda c, d:c*d, [_x[int(i)] for i in x]) if x in eq else x, 
  reduce(lambda c, d:c*d, [_x[int(i)] for i in (y[1:] if y.startswith('-') else y)] if y != 'X' else [1])
  ), eq)

print(final_result)
x = _x
print(x[1]*x[2] + x[2] + x[3] - x[1]*x[2]*x[3] - x[1] + 1)

Output:

-10
-10

But again, a predefined function is much easier to read and scale.

Also, slightly shorter, with sum :

new_result = sum([1, -1][i.startswith('-')]*reduce(lambda x, y:x*y, [1] if i == 'X' else [x[int(c)] for c in (i[1:] if i.startswith('-') else i)]) for i in eq)

Clearly I recommend the def implementation:

from functools import reduce

eq = ['12', '2', '3', '-123', '-1', 'X']
x = [n for n in range(100)]

# Using an auxiliary function
def evaluate(n):
    if n == "X":
        return 1
    elif n[0] == "-":
        return reduce(lambda x, y: x * y, [x[int(y) - 1] for y in n[1:]])
    else:
        return reduce(lambda x, y: x * y, [x[int(y) - 1] for y in n])

print(sum(map(evaluate, eq)))

# As a pure lambda:

evaluate_lambda = lambda n: sum(map((lambda n: 1 if n == 'X' else (reduce(lambda x, y: x * y, [x[int(y) - 1] for y in n[1:]]) if n[0] == "-" else reduce(lambda x, y: x * y, [x[int(y) - 1] for y in n]))), eq))

print(evaluate_lambda(eq))

that's a bit ugly but it works

from operator import mul
a = lambda eq: sum([reduce(mul, [int(x) if x.isdigit() else [1,-1][x=='-'] for x in s]) for s in eq])


print(a(['12', '2', '3', '-123', '-1', 'X']))  # outputs 1
print(a(['126', '32', '3', '-2', 'X']))  # outputs 20

edit: of course this is just a game. always use the most readable function

I think this is simple enough:

from operator import mul
from functools import reduce
prod = lambda L: reduce(mul, L, 1)
evaluateList = lambda(x, eq): sum(
    1 if expr == 'X' 
    else prod(-1 if i == '-' 
              else x[int(i)] 
              for i in expr) 
    for expr in eq)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM