trimming words in a list of strings - python

I'm writing some code that trims down a words in a list of string. if the last character of a word in the string is 't' or 's' it is removed and if the first character is 'x' it is removed.
words = ['bees', 'xerez']
should return:
['bee', 'erez']
So far my solution is:
trim_last = [x[:-1] for x in words if x[-1] == 's' or 't']
I think this trims the last characters fine. I then to trim the first characters if they are 'x' with this line:
trim_first = [x[1:] for x in trim_last if x[0] == 'x']
but this just returns an empty list, can i some how incorporate this into one working line?

[v.lstrip('x').rstrip('ts') for v in words]

You're doing a filter, not a mapping.
The right way would be
trim_first = [x[1:] if x.startswith('x') else x for x in trim_last]
Also, your solution should not return an empty list since the filter would match on the second element

In one step with re.sub() function:
import re
words = ['bees', 'xerez']
result = [re.sub(r'^x|[ts]$', '', w) for w in words]
print(result)
The output:
['bee', 'erez']

Just to chime in - since this is in fact, a mapping:
map(lambda x: x[1:] if x[0] == 'x' else x, words)

If you are looking for a one-liner you can use some arithmetic to play with the list slicing:
words = ['bees', 'xerez', 'xeret']
[w[w[0] == 'x' : len(w) - int(w[-1] in 'st')] for w in words]
# output: ['bee', 'erez', 'ere']

You can try this code:
trim_last = [x.lstrip('x').rstrip('t').rstrip('s') for x in words]

Why you are using two list comprehension for that you can do with one list comprehension :
one line solution:
words = ['bees', 'xerez','hellot','xnewt']
print([item[:-1] if item.endswith('t') or item.endswith('s') else item for item in [item[1:] if item.startswith('x') else item for item in words]])
output:
['bee', 'erez', 'hello', 'new']
Explanation of above list comprehension :
final=[]
for item in words:
sub_list=[]
if item.endswith('t') or item.endswith('s'):
sub_list.append(item[:-1])
else:
sub_list.append(item)
for item in sub_list:
if item.startswith('x'):
final.append(item[1:])
else:
final.append(item)
print(final)

Related

Evaluating a lambda function with if else f'y{x}' inside the sorted method

I have the following sorting problem:
Given a list of strings, return the list of strings
sorted, but group all strings starting with 'x' first.
Example: ['mix', 'banana' ,'xyz', 'apple', 'xanadu', 'aardvark']
Will return: ['xanadu', 'xyz', 'aardvark', 'apple', 'banana' ,'mix']
I solved by splitting the list into 2:
def front_x(words):
return [w for w in words if w[0] == "x"] + [w for w in words if w[0] != "x"]
Another pythonic solution for this problem would be using sorted method, like this:
def front_x(words):
return sorted(words, key=lambda x: x if x[0] == 'x' else f'y{x}')
I am having a hard time to understand what is going on after else. Any good soul to help me out? I'm grateful.
return sorted(words, key=lambda x: x if x[0] == 'x' else f'y{x}')
Translation:
"Return a sorted version of words. For each item x in words, use x for comparison when sorting, but only if x[0] is equal to the character 'x'. Otherwise, append 'y' to the front of x and use that for comparison instead"
The f'y{x}' syntax is the f-string syntax. It's equivalent to:
"y" + str(x)
There are plenty of other equivalent ways to insert a character into a string. That's just how it's being done here.
So, if your word list was:
aardvark
xylophone
xamarin
xenophobia
zipper
apple
bagel
yams
The list would be sorted as if it contained the following:
yaardvark
xylophone
xamarin
xenophobia
yzipper
yapple
ybagel
yyams
And therefore the output would be:
xamarin
xenophobia
xylophone
aardvark
apple
bagel
yams
zipper
So, what is happening is that, when the list is sorted, items that start with 'x' will always appear before any other items.
f'y{x}' in an f-string expression that prepends the character 'y' to the original string (x). That way, all items that don't start with 'x' will sort as if they started with 'y', which puts them after all of the items that do start with 'x'.
For example, 'banana' will be sorted as if it was 'ybanana', which naturally places it after 'xyz'.

How can you sort a string backwords, by vowels and consonant?

So I have to create a program that rewrites a string backword and alternates vowels and consonants like in this example:
ex_1:
input -> 'abcdefi'
output -> 'ifedacb'
ex_2:
input -> 'vblsdeloai'
output ->'iladoselbv'
What I did so far:
word = input('the word is: ')
b = word[::-1]
list_vowels = []
list_consonants = []
final_list = []
string = ''
vowels = ['a', 'e','i','o','u']
for i in str(b):
if i in vowels:
list_vowels.append(i)
elif i not in vowels:
list_consonants.append(i)
part where I'm stuck
for j in list_vowels :
final_list.append(j)
for b in list_consonants :
final_list.append(b)
converts my final list into a string
for q in e
string = string + e
print (string)
so I convert the string backwords than I use a for to iterate over every char and compare it to the vowel list. If it is in the vowel list then append to a new list list_vowels if not append it to a new list list_consonants.
Now I'm stuck at the part where I have to create a list that is created by the two list list_vowels and list_consonats. I don't now how can I make the two for work simultaniously. The zip functions make the list a tuple and I don't think I can use that. I'm prety new and any help will be awsome. If you think I can aproach this problem differently feel free to tell me I am new to programing and I don't realy now how.
You need itertools.zip_longest to zip through two lists taking an empty string as fillvalue:
''.join(map(lambda x: x[0] + x[1], zip_longest(list_vowels, list_consonants, fillvalue='')))
Code:
from itertools import zip_longest
word = input('the word is: ')
b = word[::-1]
list_vowels = []
list_consonants = []
final_list = []
string = ''
vowels = ['a', 'e','i','o','u']
for i in b:
if i in vowels:
list_vowels.append(i)
elif i not in vowels:
list_consonants.append(i)
print(''.join(map(lambda x: x[0] + x[1], zip_longest(list_vowels, list_consonants, fillvalue=''))))
The line you're missing is turning your two list of 1) vowels and 2) consonants into a zipped string. You can do this with itertools.zip_longest().
This is the line you will need:
from itertools import zip_longest
''.join(''.join(x) for x in zip_longest(list_vowels, list_consonants, fillvalue=''))
In[1]: 'vblsdeloai'
Out[1]: 'iladoselbv'
from itertools import zip_longest
def split(s):
vowels = ['a', 'e', 'i', 'o', 'u']
return list(filter(lambda c: c in vowels, s)), \
list(filter(lambda c: c not in vowels, s))
def reverse_interleave(s):
vowels, consonants = list(map(reversed, split(s)))
return ''.join(
map(lambda x: ''.join(x),
zip_longest(vowels, consonants, fillvalue='')))
print(reverse_interleave('abcdefi'))
print(reverse_interleave('vblsdeloai'))
Split the characters into vowels and non-vowels.
Reverse them.
Interleave them using zip_longest() in this case.

remove a string in list

I have a nested list (l1) containing several lists of sentences (i) and I want to remove a particular string from the second element in (i) when the split() method is applied to it. However it seems that only half of them are removed and the rest remain.
This is what I have tried:
for i in l1:
for j in i[1].split():
if j == 'a':
i[1].split().remove(j)
I have also tried to replace (j) with an empty string, but it wasn't helpful either.
example input: [[string1, This is a book], [string2, He is a tall man], ,,,]
example output:
This is book, He is tall man
You can't mutate the string, so your example won't work.
But you can mutate lists, so you could split the string on whitespace, ignore 'a' tokens and join it back together again:
for i in l1:
i[1] = ' '.join(p for p in i[1].split() if p != 'a')
This would eat any extra whitespace in the original string, but I'm assuming that's not a concern for you here.
This following code:
l1 = [
[None, "This is a dog"],
[None, "He is a tall man"],
]
for i in l1:
sentence = i[1]
new_sentence = []
for word in sentence.split():
if word == 'a':
continue
new_sentence.append(word)
i[1] = " ".join(new_sentence)
print(l1)
will result in
[
[None, 'This is dog'],
[None, 'He is tall man']
]
If I understand you properly this should accomplish what you're trying to do.
for i in l1:
if 'a' in i[1]:
i[1] = i[1].replace(' a ', ' ')
A solution a little bit more efficient I think:
word_search = 'a'
for i in l1:
split_sentence = i[1].split()
if word_search in split_sentence:
while word_search in split_sentence:
split_sentence.remove(word_search)
i[1] = ' '.join(split_sentence)
This solution doesn't loop through the sentence and doesn't do the join in case the searched word is not found in the sentence.
This depends on the frequency of the searched word in all the sentences I guess.

Del part of list in python by for loop

I am trying to remove some words from string list of words.
list1= "abc dfc kmc jhh jkl".
My goal is to remove the words from 'dfc' to 'jhh'. I am new in Python, so I am trying some things with the index from c#, but they don't work here.
I am trying this:
index=0
for x in list1:
if x=='dfc'
currentindex=index
for y in list1[currentindex:]
if y!='jhh'
break;
del list1[currentindex]
currentindex=index
elif x=='jhh'
break;
Instead of a long for loop, a simple slice in Python does the trick:
words = ['abc', 'dfc', 'kmc', 'jhh', 'jkl']
del words[1:4]
print(words)
indexes start at 0. So you want to delete index 1-3. We enter 4 in the slice because Python stops -1 before the last index argument (so at index 3). Much easier than a loop.
Here is your output:
['abc', 'jkl']
>>> a = "abc dfc kmc jhh jkl"
>>> print(a.split("dfc")[0] + a.split("jhh")[1])
abc jkl
You can do this sample treatment with lambda:
b = lambda a,b,c : a.split(b)[0] + a.split(c)[1]
print(b(a, "dfc", "jhh"))
First, split the string into words:
list1 = "abc dfc kmc jhh jkl"
words = list1.split(" ")
Next, iterate through the words until you find a match:
start_match = "dfc"
start_index = 0
end_match = "jhh"
end_index = 0
for i in range(len(words)):
if words[i] == start_match:
start_index = i
if words[i] == end_match:
end_index = j
break
print ' '.join(words[:start_index]+words[end_index+1:])
Note: In the case of multiple matches, this will delete the least amount of words (choose the last start_match and first end_match).
list1= "abc dfc kmc jhh jkl".split() makes list1 as follows:
['abc', 'dfc', 'kmc', 'jhh', 'jkl']
Now if you want to remove a list element you can try either
list1.remove(item) #removes first occurrence of 'item' in list1
Or
list1.pop(index) #removes item at 'index' in list1
Create a list of words by splitting the string
list1= "abc dfc kmc jhh jkl".split()
Then iterate over the list, using a flag variable to indicate whether an element should be deleted from the list
flag = False
for x in list1:
if x=='dfc':
flag = True
if x == 'jhh':
list1.remove(x)
flag = False
if flag == True:
list1.remove(x)
There are several problems with what you have tried, especially:
list1 is a string, not a list
when you write list1[i], you get the character at index i (not a word)
in your for loop, you try to modify the string you iterate on: it is a very bad idea.
Here is my one-line style suggestion using re.sub(), which simply substitute a part of the string matching with the given regex pattern. It may be sufficient for your purpose:
import re
list1= "abc dfc kmc jhh jkl"
list1 = re.sub(r'dfc .* jhh ', "", list1)
print(list1)
Note: I kept the identifier list1 even if it is a string.
You can do like this
test = list1.replace("dfc", "")

filter string in comprehension list with nested loops

I want just for fun know if it's possible process this in a comprehension
list
some like:
text = "give the most longest word"
def LongestWord(text):
l = 0
words = list()
for x in text.split():
word = ''.join(y for y in x if y.isalnum())
words.append(word)
for word in words:
if l < len(word):
l = len(word)
r = word
return r
Not one but two list comprehensions:
s = 'ab, c d'
cmpfn = lambda x: -len(x)
sorted([''.join(y for y in x if y.isalnum()) for x in s.split()], key=cmpfn)[0]
Zero list comprehensions:
import re
def longest_word(text):
return sorted(re.findall(r'\w+', text), key=len, reverse=True)[0]
print(longest_word("this is an example.")) # prints "example"
Or, if you insist, the same thing but with a list comprehension:
def longest_word(text):
return [w for w in sorted(re.findall(r'\w+', text), key=len, reverse=True)][0]
No need for a list comprehension, really.
import re
my_longest_word = max(re.findall(r'\w+', text), key=len)
Alternatively if you don't want to import re, you can avoid a lambda expression and use one list comprehension using max once again:
my_longest_word = max([ ''.join(l for l in word if l.isalnum())
for w in text.split() ], key = len)
How this works:
Uses a list comprehension and isalnum() to filter out non-alphanumeric characters evaluating each letter in each word, and splits into a list using whitespaces.
Takes the max once again.
How regex solution works:
Matches all alphanumeric of at least length 1 with \w+
findall() places the matches in a list of strings
Max finds the element with maximum length from the list.
Outputs (in both cases):
>>>text = "give the most longest word"
>>>my_longest_word
'longest'
>>>text = "what!! is ??with !##$ these special CharACTERS?"
>>>my_longest_word
'CharACTERS'

Categories