2
expr='9subtract5equal4'

expr = expr.replace('subtract', '-')
expr = expr.replace('plus', '+')
expr = expr.replace('equal', '==')

I feel the last three lines code are very ugly, so I've tried to optimize using map and other functional programming functions. But I did't find a good way to achieve that. Any suggestions?

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
WW00WW
  • 417
  • 4
  • 15

5 Answers5

5

You could do something like this:

def replace_all(text, dic):
  for i, j in dic.items():
    text = text.replace(i, j)
  return text

s = '9subtract5equal4'

d = {
  'subtract': '-',
  'plus': '+',
  'equal': '==',
}

s = replace_all(s, d)
Colin Ricardo
  • 16,488
  • 11
  • 47
  • 80
2

As it is the code is fine but you could operate directly on the return value at each step:

expr='9subtract5equal4'

expr = expr.replace('subtract', '-') \
    .replace('plus', '+') \
    .replace('equal', '==') 

Or even

expr = '9subtract5equal4' \
    .replace('subtract', '-') \
    .replace('plus', '+') \
    .replace('equal', '==') 
Robert Sim
  • 1,428
  • 11
  • 22
2

You could just do:

expr = expr.replace('subtract', '-').replace('plus', '+').replace('equal', '==')

Or, you could loop through a dictionary of replacements:

replace = {'subtract': '-', 'plus': '+', 'equal': '='}
for word in replace:
    expr = expr.replace(word, replace[word])
Adi219
  • 4,712
  • 2
  • 20
  • 43
  • you could also use regex define a lambda: "repl = lambda x: expr[x.group(0)]" then call "re.sub('subtract|equal', string="9subtract5equal4", repl=repl)" where expr is a dict with your replacements –  Apr 29 '18 at 15:02
2
  1. Create a dictionary that maps from operand name to the symbol:

    ops = {'subtract':'-', 'add':'+', 'equal':'=='}
    

    You can make it as long as you want, which clearly is an optimisation – adding more operands is extremely easy and does not need any further modification.

  2. Loop over your expression using a list comprehension:

    [x if x.isdigit() else ops[x] for x in re.findall(r'\d+|[a-z]+',expr)]
    

    This uses a regex to separate digits and operands, so import re at the start. The regex returns

    ['9', 'subtract', '5', 'equal', '4']
    

    and the list comprehension replaces not-digit strings with the items from the dictionary.

Result:

['9', '-', '5', '==', '4']

so you'd use

expr = ''.join([x if x.isdigit() else ops[x] for x in re.findall(r'\d+|[a-z]+',expr)])

to get your output

'9-5==4'
Jongware
  • 22,200
  • 8
  • 54
  • 100
1

Honestly, I would write it the way you wrote it, but if you want to do it "functionally" you probably need to use functools.reduce, as you need to "reduce" a list of substitutions into a single result:

import functools

expr = '9subtract5equal4'

# a list of our replacements, as pairs
REPLACEMENTS = [
    ('subtract', '-'),
    ('plus', '+'),
    ('equal', '=='),
]

result = functools.reduce(
    lambda word, old_new: word.replace(old_new[0], old_new[1]),
    REPLACEMENTS,
    expr
)

Here we just "accumulate" the results of the lambda function, which takes the last "accumulated" word and a substitution pair, and calls .replace() to get the next "accumulated" word.

But really this is not a Pythonic way to solve this problem (there is a reason why reduce got shoved into functools in Python 3), and your original approach is better.

Joel
  • 507
  • 4
  • 11