简体   繁体   中英

Applying a dictionary of string replacements to a list of strings

Say I have a list of strings and a dictionary specifying replacements:

Eg

my_replacements = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}

and a list of strings, where each string can possibly include keys from the above dictionary, eg:

['I own 1/2 bottle', 'Give me 3/4 of the profit']

How can I apply the replacements to the list? What would be a Pythonic way to do this?

O(n) solution:

reps = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}
li = ['I own 1/2 bottle', 'Give me 3/4 of the profit']

map(lambda s: ' '.join([reps.get(w,w) for w in s.split()]),li)
Out[6]: ['I own half bottle', 'Give me three quarters of the profit']

#for those who don't like `map`, the list comp version:
[' '.join([reps.get(w,w) for w in sentence.split()]) for sentence in li]
Out[9]: ['I own half bottle', 'Give me three quarters of the profit']

The issue with making lots of replace calls in a loop is that it makes your algorithm O(n**2). Not a big deal when you have a replacement dict of length 3, but when it gets large, suddenly you have a really slow algorithm that doesn't need to be.

As noted in comments, this approach fundamentally depends on being able to tokenize based on spaces - thus, if you have any whitespace in your replacement keys (say, you want to replace a series of words) this approach will not work. However being able to replace only-words is a far more frequent operation than needing to replace groupings-of-words, so I disagree with the commenters who believe that this approach isn't generic enough.

a = ['I own 1/2 bottle', 'Give me 3/4 of the profit']
b = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}

def replace(x):
    for what, new in b.items(): # or iteritems in Python 2
        x = x.replace(what, new)
    return x

print(list(map(replace, a)))

Output:

['I own half bottle', 'Give me three quarters of the profit']

I'd use something like this:

def replace_all(replacements, s):
    for old, new in replacements.items():
        s = s.replace(old, new)
    return s

my_replacements = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}
strings = ['I own 1/2 bottle', 'Give me 3/4 of the profit']

print ", ".join(replace_all(my_replacements, x) for x in strings)

Output:

I own half bottle, Give me three quarters of the profit

If you expect the strings in the list to have many matches and are doing the replacements for my_replacements for a large size list or on many lists, then it might make sense to construct a pattern and use re.sub . The following solution, unlike user2931409 doesn't require any special structure to the replacements, and it should perform at least as well as roippi's solution, because it doesn't make multiple passes over the input strings either:

import re

my_replacements = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}

l = ['I own 1/2 bottle', 'Give me 3/4 of the profit']

def do_replacement(match):
    return my_replacements[match.group(0)]

r = re.compile('|'.join('(?:%s)' % (re.escape(k)) for k in my_replacements.keys()))

[r.sub(s, do_replacement) for s in l]

Use re.sub .

import re

my_replacements = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}
strings = ['I own 1/2 bottle', 'Give me 3/4 of the profit']

print [re.sub(r'\d/\d', lambda x: my_replacements[x.group()], string) for string in strings]

output:

['I own half bottle', 'Give me three quarters of the profit']

I have used Dictionary-Based Formatting Expressions .

Docs: https://docs.python.org/2/library/string.html#format-examples

my_replacements = {'1/2': 'half', '1/4': 'quarter', '3/4': 'three quarters'}
c = 'I own %(1/2)s bottle, Give me %(3/4)s of the profit' % my_replacements
print(c)
# I own half bottle, Give me three quarters of the profit

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