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?

6
  • 2
    What does 'optimize' mean? Run faster? Use less characters? Use less run-time memory? Commented Apr 29, 2018 at 14:23
  • Codereview Commented Apr 29, 2018 at 14:25
  • 2
    Perhaps maintain a dictionary of replacements. Commented Apr 29, 2018 at 14:29
  • @usr2564301 I want to use less characters. Commented Apr 29, 2018 at 14:38
  • 1
    @Georgy Thank you very much, that's exactly what I want! And sorry for my poor search ability... Commented Apr 29, 2018 at 14:51

5 Answers 5

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)
Sign up to request clarification or add additional context in comments.

Comments

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])

1 Comment

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
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', '==') 

Comments

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'

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.