Replacing several strings in a list in a single statement - python

I am trying to replace the third and forth words of this list by two different words in one single statement and just can't seem to find of doing it what I tried doesn't work with the error AttributeError: 'list' object has no attribute 'replace':
friends = ["Lola", "Loic", "Rene", "Will", "Seb"]
friends.replace("Rene", "Jack").replace("Will", "Morris")

If you want to do multiple replacements probably the easiest way is to make a dictionary of what you want to replace with what:
replacements = {"Rene": "Jack", "Will": "Morris"}
and then use a list comprehension:
friends = [replacements[friend] if friend in replacements else friend for friend in friends]
Or more compactly, using dict.get() with a default value.
friends = [replacements.get(friend, friend) for friend in friends]

Another way, if you don't mind the overhead of converting the list to a pandas.Series:
import pandas as pd
friends = ["Lola", "Loic", "Rene", "Will", "Seb"]
friends = pd.Series(friends).replace(to_replace={"Rene":"Jack", "Will":"Morris"}).tolist()
print(friends)
#['Lola', 'Loic', 'Jack', 'Morris', 'Seb']

This is a not so pretty solution, but a one-liner nevertheless:
friends = list(map(lambda x: x if x != "Will" else "Morris", map(lambda x: x if x != "Rene" else "Jack", friends)))
Brief explanation:
It's a "map(lambda, list)" solution, whose output list is passed as input list to another outer "map(lambda, list)" solution.
The lambda in the inner map is for replacing "Will" with "Morris".
The lambda in the outer map is for replacing "Rene" with "Jack"

Related

How to sort a list by integer between two values?

I have the following list:
['RC103_', 'RC109_', 'RC114_', 'RC115_', 'RC111_', 'RC100_', 'RC117_', 'RC104_', 'RC122_', 'RC120_', 'RC101_', 'RC121_', 'RC125_', 'RC116_', 'RC118_', 'RC119_', 'RC102_', 'RC129_', 'RC126_', 'RC12_4']
If I try to sort this list, I get this output:
['RC100_', 'RC101_', 'RC102_', 'RC103_', 'RC104_', 'RC109_', 'RC111_', 'RC114_', 'RC115_', 'RC116_', 'RC117_', 'RC118_', 'RC119_', 'RC120_', 'RC121_', 'RC122_', 'RC125_', 'RC126_', 'RC129_', 'RC12_4']
How can I sort this list so that RC12_4 is at the top? To be clear, I want this:
['RC12_4', 'RC100_', 'RC101_', 'RC102_', 'RC103_', 'RC104_', 'RC109_', 'RC111_', 'RC114_', 'RC115_', 'RC116_', 'RC117_', 'RC118_', 'RC119_', 'RC120_', 'RC121_', 'RC122_', 'RC125_', 'RC126_', 'RC129_']
What I want to do is sort by the value between 'RC' and the underscore. I know that to sort by, for instance, the first group created by '_' is to use:
sorted(listName, key=lambda x: x.split('_')[0])
Is there a way to modify this script so that it sorts by the first item after RC and before the underscore? Or is there an easier way?
Also I have tried the natural keys approach and it didn't work for me.
Convert it to int:
sorted(listName, key=lambda x: int(x.split('_')[0][2:]))

Keep only two part on element within a python list

I'm looking for a commande in python in order to only keep within a list the 3 first letters between content_content > con_con
here is an example:
list_exp=["Babylona_expetiendra","Ocracylus_machabrus","Ojeris_multifasciatus"]
list_exp=["Bab_exp","Ocr_mac","Oje_mul"]
Does anyone have an idea? Thank you for your help .
You can use a list-comprehension:
['_'.join(map(lambda x: x[:3], x.split('_'))) for x in list_exp]
Code:
list_exp=["Babylona_expetiendra","Ocracylus_machabrus","Ojeris_multifasciatus"]
print(['_'.join(map(lambda x: x[:3], x.split('_'))) for x in list_exp])
# ['Bab_exp', 'Ocr_mac', 'Oje_mul']
[
*map(
lambda strip:'_'.join([st[:3] for st in strip]),
[
*map(
lambda s:s.split('_'),
["Babylona_expetiendra","Ocracylus_machabrus","Ojeris_multifasciatus"]
)
]
)
]
mess explanation:
First we are splitting every string in list by '_' gigving us
[['Babylona', 'expetiendra'], ['Ocracylus', 'machabrus'], ['Ojeris', 'multifasciatus']]
Then we are getting first 3 letters using [:3] for every string inside new lists
Finnaly joining again with '_'.join()
['Bab_exp', 'Ocr_mac', 'Oje_mul']
This example using map unpacking and lamdas
You can try like this.
Before running all these, just have a quick look at the use of list comprehension & join(), split() methods defined on strings.
>>> list_exp = ["Babylona_expetiendra","Ocracylus_machabrus","Ojeris_multifasciatus"]
>>>
>>> output = ['_'.join([part[:3] for part in name.split("_")]) for name in list_exp]
>>> output
['Bab_exp', 'Ocr_mac', 'Oje_mul']
>>>

How to filter a list without converting to string or loop it

I've got an object of type list and second object of type string.
I would like to filter for all values in the list-object which do not match the value of the string-object.
I have created a loop which splits the list into string and with regex found all those not matching and added these results to a new list.
This example uses hostnames "ma-tsp-a01", "ma-tsp-a02" an "ma-tsp-a03".
Currently I do further work on this new list to create a clean list of hostnames.
import re
local_hostname = 'ma-tsp-a01'
profile_files = ['/path/to/file/TSP_D01_ma-tsp-a01\n', \
'/path/to/file/TSP_D02_ma-tsp-a02\n', \
'/path/to/file/TSP_ASCS00_ma-tsp-a01\n', \
'/path/to/file/TSP_DVEBMGS03_ma-tsp-a03\n', \
'/path/to/file/TSP_DVEBMGS01_ma-tsp-a01\n']
result_list = [local_hostname]
for list_obj in profile_files:
if re.search(".*\w{3}\_\w{1,7}\d{2}\_(?!"+local_hostname+").*", list_obj):
result_list.append(list_obj.split("/")[-1].splitlines()[0].\
split("_")[-1])
print(result_list)
At the end I get the following output
['ma-tsp-a01', 'ma-tsp-a02', 'ma-tsp-a03']. This looks exactly what I am searching for. But is there a way to make this in a more pythonic way without the "for" loop?
You can create a filter object:
filtered = filter(lambda x: re.search(".*\w{3}\_\w{1,7}\d{2}\_(?!"+local_hostname+").*", x), profile_files)
Or use a generator comprehension:
filtered = (x for x in profile_files if re.search(".*\w{3}\_\w{1,7}\d{2}\_(?!"+local_hostname+").*", x))
Both behave the same

Comparing and returning dictionary string values?

Trying to make a function that returns a list of values from the dictionary. If the plants are watered weekly, it would be appended into the list then later returned sorted. However, my code iterates each letter of 'weekly' instead of the whole string and I have no idea how to access the watering frequency of the dictionary items. Any explanations would be appreciated.
def weekly(plants_d):
d = []
for plant in plants_d:
for plan in plants_d[plant]:
if plan == "weekly":
d.append[plan]
return sort(d)
weekly({'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly'})
# Should return like this: ['carnation','fern','shamrock']
Amending the previous answer so that only values with "weekly" are used:
>>> my_dict = {'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly', 'daffodil': 'monthly'}
>>> sorted(k for k, v in my_dict.items() if v == 'weekly')
['carnation', 'fern', 'shamrock']
This line:
for plan in plants_d[plant]:
is wrong. Since plants_d[plant] is a string like "weekly", this is like
for plan in "weekly":
which will iterate over the letters in the string. Then when you do if plan == "weekly": it will never match, because plan is just a single letter like "w".
You can simply use:
if plants_d[plan] == "weekly":
Or you can change the first loop to:
for plan_name, plan_frequency in plants_d.items():
if plan_frequency == "weekly":
d.append[plan_name]
See Iterating over dictionaries using 'for' loops
Simplified way to achieve this is using dict.keys() which return the list of all the keys in dict. In order to sort the list, you may use sorted() as:
>>> my_dict = {'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly'}
>>> sorted(my_dict.keys())
['carnation', 'fern', 'shamrock']
Edit: If some the plans are monthly, firstly filter the monthly plans using filter or dict comprehension. Your code should be like:
>>> my_dict = {'fern':'weekly', 'shamrock':'weekly', 'carnation':'weekly',
'something': 'monthly'}
# using filter() as #brianpck has already mentioned 'dict comprehension' approach
# It is better to use brian's approach
>>> filtered_dict = dict(filter(lambda x: x[1] == 'weekly', my_dict.items()))
>>> sorted(filtered_dict.keys())
['carnation', 'fern', 'shamrock']

TypeError when using replace() from dictionary

First of all: Please keep in mind that I'm very much a beginner at programming.
I'm trying to write a simple program in Python that will replace the consonants in a string with consonant+"o"+consonant. For example "b" would be replaced with "bob" and "d" would be replaced with "dod" (so the word "python" would be changed to "popytothohonon").
To do this I created a dictionary, that contained the pairs b:bob,c:coc,d:dod etc. Then I used the replace() command to read through the word and replace the consonants with their translation in the dictionary. The full piece of code looks like this:
def replacer(text):
consonant='bcdfghjklmnpqrstvwxz'
lexicon={}
for x in range(0,len(consonant)):
lexicon[x]=(consonant[x]),(consonant[x]+'o'+consonant[x])
for i,j in lexicon.items():
text=(text.replace(i,j))
return text
Now, when I try to call this function I get the following error:
Traceback (most recent call last):
File "D:\x\x.py", line 37, in <module>
print(replacer("python"))
File "D:\x\x.py", line 17, in replacer
text=(text.replace(i,j))
TypeError: Can't convert 'int' object to str implicitly
But I'm not using any ints! There's got to be something wrong with the dictionary, because everything works when i make it "by hand" like this:
list={'b':'bob', 'c':'coc', 'd':'dod', 'f':'fof', 'g':'gog', 'h':'hoh'......}
But when I print the "non-hand-made" dictionary everything seems to be in order:
{0: ('b', 'bob'), 1: ('c', 'coc'), 2: ('d', 'dod'), 3: ('f', 'fof')........
What am I doing wrong?
lexicon is a dictionary with integers as keys and tuples as values. when you iterate over it's items, you're getting tuples of the form (integer,tuple). You're then passing that integer and tuple to text.replace as i and j which is why it's complaining. Perhaps you meant:
for i,j in lexicon.values():
...
For this simple replacement, str.replace is fine, but for more complicated replacements, the code will probably be more robust (and possibly execute faster!) if you use re.sub instead.
Also, as pointed out in the comments, for this case, a better data structure would be to use a list:
lexicon = [ (x,'{0}o{0}'.format(x)) for x in chars ]
Now you can build your dict from this list if you really want:
lexicon = dict(enumerate(lexicon))
but there's probably no need. And in this case, you'd iterate over lexicon directly:
for i,j in lexicon:
...
If you're only going to do this once, you could even do it lazily without ever materializing the list by using a generator expression:
lexicon = ( (x,'{0}o{0}'.format(x)) for x in chars )
I guess what you wanted to achieve is lexicon mapping consonant to replacement. It may be done this way:
lexicon = { c: c+'o'+c for c in consonant }
which is equivalent of:
for c in consonant:
lexicon[c] = c+'o'+c
No need for dictionaries this time, just iterate over characters of text, add vovels or consonant+o+consonant to an result array and join it to a string at the end:
def replacer(text):
consonants = set('bcdfghjklmnpqrstvwxz')
result = []
for c in text:
if c in consonants:
result.append(c+"o"+c)
else:
result.append(c)
return "".join(result)
print(replacer("python"))
For advanced users:
def replacer(text):
return re.sub(r"[bcdfghjklmnpqrstvwxz]", r"\g<0>o\g<0>", text)
And to answer "What am I doing wrong?" - dictionaries are useful for arbitrary keys, usually list.append() is preferred from using keys 0-n in a dict. And since you are not interested in a consonant's position, you can iterate over strings directly like this:
for x in consonant:
lexicon[x] = x+"o"+x
no ... your keys in the handmade version are strings ... your kets in the other version are ints ... ints have no replace method

Categories