I guess the word_list(try to rename the variable to word_dict, I think that is more appropriate) has lots of items,
for index, data in enumerate(sentence):
for key, value in word_list.iteritems():
if key in data:
sentence[index]=data.replace(key, word_list[key])
working example from ipython
In [1]: word_list = { "hello" : "1", "bye" : "2"}
In [2]: sentence = ['hello you, hows things', 'hello, good thanks']
In [3]: for index, data in enumerate(sentence):
...: for key, value in word_list.iteritems():
...: if key in data:
...: sentence[index]=data.replace(key, word_list[key])
...:
In [4]: sentence
Out[4]: ['1 you, hows things', '1, good thanks']
Answer from Jithin on Stack OverflowI guess the word_list(try to rename the variable to word_dict, I think that is more appropriate) has lots of items,
for index, data in enumerate(sentence):
for key, value in word_list.iteritems():
if key in data:
sentence[index]=data.replace(key, word_list[key])
working example from ipython
In [1]: word_list = { "hello" : "1", "bye" : "2"}
In [2]: sentence = ['hello you, hows things', 'hello, good thanks']
In [3]: for index, data in enumerate(sentence):
...: for key, value in word_list.iteritems():
...: if key in data:
...: sentence[index]=data.replace(key, word_list[key])
...:
In [4]: sentence
Out[4]: ['1 you, hows things', '1, good thanks']
The replacement occurs on a variable inside the loop
So nothing is changed in the sentence list
To fix this make a new list with the changed items in it
word_list = { "hello" : "1"}
sentence= ['hello you, hows things', 'hello, good thanks']
newlist=[]
for key, value in word_list.items():
for i in sentence:
i = i.replace(key, value)
newlist.append(i)
print newlist
Another way with map
word_list = { "hello" : "1"}
sentence= ['hello you, hows things', 'hello, good thanks']
newlist=[]
for key, value in word_list.items():
newlist=map(lambda x: x.replace(key,value), sentence)
print newlist
Another way with a list comprehension
word_list = { "hello" : "1"}
sentence= ['hello you, hows things', 'hello, good thanks']
newlist=[]
for key, value in word_list.items():
newlist=[x.replace(key,value) for x in sentence]
print newlist
note: updated for python3, thanks @MGM
python - How to replace elements in a list using dictionary lookup - Stack Overflow
Replace items in a list with stuff from dictionary
python 3.x - Replace a string stored in a list of dictionaries - Stack Overflow
python using a dictionary to replace characters in a list of strings - Stack Overflow
If all values are unique then you should reverse the dict first to get an efficient solution:
>>> subs = {
... "Houston": "HOU",
... "L.A. Clippers": "LAC",
...
... }
>>> rev_subs = { v:k for k, v in subs.items()} # subs.iteritems() In Python 3
>>> [rev_subs.get(item, item) for item in my_lst]
['L.A. Clippers', 'Houston', '03/03 06:11 PM', '2.13', '1.80', '03/03 03:42 PM']
If you're only trying to update selected indexes, then try:
indexes = [0, 1]
for ind in indexes:
val = my_lst[ind]
my_lst[ind] = rev_subs.get(val, val)
If the values are unique, then you can flip the dictionary:
subs = {v:k for k, v in subs.iteritems()}
Then you can use .get() to get the value from a dictionary, along with a second parameter incase the key is not in the dictionary:
print map(subs.get, my_lst, my_lst)
Prints:
['L.A. Clippers', 'Houston', '03/03 06:11 PM', '2.13', '1.80', '03/03 03:42 PM']
Hey r/learnpython have a little problem I need help solving.
So I need to make a program that gets a list of strings of shorted words of the day like: mon, tue, wed etc Then Turn the list into the full words And print it. The problem I am facing is I have no clue how to replace the words in the list with the info from the dictionary.
progression is a list. To access content from it, you need to use the index value, which is an integer, and not a string, hence the error.
You probably want:
for i, j in enumerate(words):
words[i] = clues.get(j)
What enumerate does is loops through the list of words, where i is the index value and j is the content. .get() is similar to dict['key'], but if the key is not found it returns None instead of raising an error.
Then words[i] modifies the list with the index number of the word
Haidro explained it pretty well, but I thought I'd expand his code, and also address another issue.
First off, as Inbar Rose pointed out, your naming conventions bad. It makes code much more difficult to read, debug, and maintain. Pick concise descriptive names, and make sure to follow PEP-8. Avoid re-using the same variable name for different things, especially within the same scope.
Now, to the code:
words = ['Super', 'Random', 'List']
clues = {'R': 'S', 'd': 'r', 'a': 'e', 'o': 'e', 'm': 't', 'n': 'c'}
def decrypter(words, clues):
progression = words[:]
for i, word in enumerate(progression):
for key in clues:
progression[i] = progression[i].replace(key, clues.get(key))
return progression
This now replaces characters in the content of progression[i] instead of replacing progression[i] with the key from clues.
Also, changed progression = words to progression = words[:] in order to create a copy of the list to act on. You pass in a reference to words, and then assign that same reference to progression. As you manipulate progression, so to do you manipulate words, rendering progression useless to be using in this case.
Example using:
print words
print decrypter(words, clues)
print words
Output using progression = words:
['Super', 'Random', 'List']
['Super', 'Secret', 'List']
['Super', 'Secret', 'List']
Output using progression = words[:]:
['Super', 'Random', 'List']
['Super', 'Secret', 'List']
['Super', 'Random', 'List']
I'm not sure why you're iterating over every character, assigning splitline to be the same thing every time. Let's not do that.
words = text.split() # what's a splitline, anyway?
It looks like your terminology is backwards, dictionaries look like: {key: value} not like {value: key}. In which case:
my_dict = {'the': 1, 'in': 2, 'a': 3}
is perfect to turn "the man lives in a house" into "1 man lives 2 3 house"
From there you can use dict.get. I don't recommend str.replace.
final_string = ' '.join(str(my_dict.get(word, word)) for word in words)
# join with spaces all the words, using the dictionary substitution if possible
dict.get allows you to specify a default value if the key isn't in the dictionary (rather than raising a KeyError like dict[key]). In this case you're saying "Give me the value at key word, and if it doesn't exist just give me word"
Now that you have your dict the proper way, you can do regular dict object stuff like checking for keys and grabbing values:
>>> text = 'the man lives in a house'
>>> mydict = {"the":1,"in":2,"a":3}
>>> splitlines = text.split()
>>> for word in splitlines:
if word in mydict:
text = text.replace(word,str(mydict[word]))
HOWEVER, note that with this:
>>> text
'1 m3n lives 2 3 house'
since a is a key, the a in man will be replaced. You can instead use regex to ensure word boundaries:
>>> text = 'the man lives in a house'
>>> for word in splitlines:
if word in mydict:
text = re.sub(r'\b'+word+r'\b',str(mydict[word]),text)
>>> text
'1 man lives 2 3 house'
the \b ensures that there is word boundary around each match.
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']
Use get and join:
>>> ''.join(key.get(e,'') for e in List)
'zyx'
If by 'replace' you mean to change the list to the values of the dict in the order of the elements of the original list, you can do:
>>> List[:]=[key.get(e,'') for e in List]
>>> List
['z', 'y', 'x']
key = {'a':'z','b':'y','c':'x'}
List = ['a','b','c']
print([key.get(x,"No_key") for x in List])
#### Output ####
['z', 'y', 'x']
If your interest is only to print them as string,then:
print(*[key.get(x,"No_key") for x in List],sep="")
#### Output ####
zxy
Just in case you need the solution without join.
ss = ''
def fun_str(x):
global ss
ss = ss + x
return(ss)
print([fun_str(x) for x in List][-1])
#### Output ####
zxy
Just use str.replace multiple times...
string = 'Hello %*& World'
repl = ['%','*','&'], ['pct','star','and']
for a, b in zip(*repl):
string = string.replace(a, b)
However, such a way of storing replacements doesn't look good. One possibility is to use a dictionary:
repl = {'*': 'star', '%': 'pct', '&': 'and'}
for a, b in repl.items():
string = string.replace(a, b)
Also, if you know that the strings that are to be replaced are always just one character, str.translate can be more efficient. Use it like this:
repl = {'*': 'star', '%': 'pct', '&': 'and'}
repl = str.maketrans(repl)
string = string.translate(repl)
You can create a dictionary
>>> char_replace = {"%":"pct" , "*":"star" , "&":"and"}
>>> st = 'Hello %*& World'
>>> for i,j in char_replace.items():
... st = st.replace(i,j)
...
>>> st
'Hello pctstarand World'
>>>
Just out of curiosity I tried to time all the ways to replace string characters discussed here. In case you were wondering which is better.
1st way
>>> setup= '''
... char_replace = {"%":"pct" , "*":"star" , "&":"and"}
... st = 'Hello %*& World'
... for i,j in char_replace.items():
... st = st.replace(i,j)
... '''
>>> t = Timer(setup)
>>> t.timeit()
2.3223999026242836
>>>
2nd way
>>> setup1 = '''
... string = 'Hello %*& World'
... repl = ['%','*','&'], ['pct','star','and']
... for a, b in zip(*repl):
... string = string.replace(a, b)
...
... '''
>>> t = Timer(setup1)
>>> t.timeit()
3.2493382405780267
3rd way
>>> setup2 = '''
... string = 'Hello %*& World'
... repl = {'*': 'star', '%': 'pct', '&': 'and'}
... repl = str.maketrans(repl)
... string = string.translate(repl)
...
... '''
>>> t = Timer(setup2)
>>> t.timeit()
3.3588874718125226
>>>
I would prefer to take Iterable[tuple[str, Iterable[str]]] rather than dict[str, list[str]] for two reasons:
Iterableallows for a wider range of inputs than binding to concrete types.Adding
.items()in the function call is largly an irrelevant change.print(replace_in_string(TextFileContent, replacements.items()))
terms = copy.deepcopy(replacements)
IIRC deep copy will copy all of the values in the dictionary, even the strings. We can reduce the memory usage by only 'copying' the dictionary and setting the values to iterators (iter) and then advancing the iterator in replace_func.
terms = {k: iter(vs) for k, vs in replacements.items()}
def replace_func(m):
return next(terms[m.group()])
Tests
It's nice to see that you have included various tests to verify that replace_in_string works as expected.
Docstring
Its great that you have provided a docstring, but I think it could be a bit more descriptive (argument string is not even mentioned). For example:
"""
string: a str.
replacements: a dictionary whose keys are strings and whose values
are lists of string replacements.
For each key in replacements, search string for occurrences
of that key replacing each occurrence with successive elements
of the key's value.
"""
Methodology
Using re.sub seems to be the best approach to string replacement.
Will you ever have a situation where you might wish to ensure that a string being replaced is on a word boundary? In that case you could surround the key with r'\b', but then calling re.escape on the key would not work. So your keys will already need to be regular expressions that do not need escaping. Would it be useful to have an additional argument, e.g. is_regex, that defaults to False but when True means that the keys are already regular expressions that should not be escaped?
Recommendation and Alternatives
I think it's indicative of something being amiss if there are too few values for any key in replacements. Consequently, in your alternative implementation of replace_func my preference would be for you to either raise an Exception or at least issue a warning for this situation.
An alternative would be to provide an extra, optional argument to your function, e.g. strict_mode=True, which causes behavior as just described but when False, issues no warnings or exceptions.
Another alternative is to define the function so that the last replacement value for a key is never popped; there is always at least one element in the value list for any key. This remaining value will be used for all subsequent replacements. In that way, you can replace all occurrences of a string with the same value just by having a replacement list consisting of a single element. The only error situation now would be to define an empty list as the value for a key.
I want the replace a word given by the input to create a cipher, but I can’t figure out how to change each value at the same time to produce a new string.
For example the dictionary is {a: b, b: c, c: 2….} Then I want the inputted string to change each letter in the string/word to what it corresponds to in the dictionary so that a new string is generated with no letters remaining the same.
Right now this is my code:
cipher = input('Please enter the cipher text:')
import string
letters = string.ascii_lowercase
letters_list = list(letters)
cipher_list = list(cipher)
pair_letters_cipher = zip(letters_list, cipher_list)
dict_cipher = dict(pair_letters_cipher)
string_encode = input('Please enter text to encode:')
for letters, cipher in dict_cipher.items():
string_encode = string_encode.replace(letters.lower(), cipher) print(string_encode)