If I have a list similar to
mylist = ["danny","florence","micheal","klrv","yrcv"]
And I want to remove the strings that do not have vowels in them and put them in a new list, resulting in me have two lists. How do I do it?
I tried coding it manually
mylist_no_vowel = ["klrv","yrcv"]
Then using .remove to make original list smaller.
But I feel there is a code to automate it instead of doing it manually.
The quick-and-dirty one-liner is:
mylist = ["danny","florence","micheal","klrv","yrcv"]
mylist_no_vowel = [word for word in mylist if not any(character in 'aeiou' for character in word)]
Explanation
The second line uses a syntax called a list comprehension, which is a Python idiom for building a list (in this case, by filtering another list). The code is equivalent to:
mylist = ["danny","florence","micheal","klrv","yrcv"]
mylist_no_vowel = []
for word in mylist:
if not any(character in 'aeiou' for character in word):
mylist_no_vowel.append(word)
Translating, we start an empty list called mylist_no_vowel, then we iterate through each word in the original list mylist. For each word, we check if any of their characters is a vowel, using the any function. If that's not the case, we add the word to the mylist_no_vowel list.
Note that I changed your starting list variable name from list to mylist, since list is actually a reserved word in Python - you're overwriting the built-in list function by naming a variable like that!
The following codes should serve the purpose.
mylist = ["danny", "florence", "micheal", "klrv", "yrcv"]
mylist_no_vowel = list(filter(lambda x: set('aeiou') & set(x)==set(), mylist))
print(mylist_no_vowel)
Here is the result, which is the same as your expected result:
['klrv', 'yrcv']
The idea is to use the anonymous function to filter out each element x of mylist that contains vowels via keeping each element x of mylist such that the intersection of set(x) and set('aeiou') is the empty set set().
Related
I have 2 lists..
list_a = ['Grapes/testfile.csv','Apples/testfile.csv','Pears/testfile.csv','Pears/testfile2.csv']
ref_list = ['Pears','Grapes','Apples']
I need to use ref_list list to order list_a.
More context, list_a will always have the string from ref_list before the / but the length of ref_list will never match that of list_a.. Also I dont want to order reverse alphabetically.
Expected Output:
ordered_list = ['Pears/testfile.csv','Pears/testfile2.csv','Grapes/testfile.csv','Apples/testfile.csv']
I've tried many variations, referencing SO but I cant get this to work.. I just cant work out a way to reference the first list here is my attempt which obviously doesn't work as its not referencing ref_list but my logic is to use string method startswith()
Something like:?
ordered_list = sorted(list_a, key = lambda x: x.startswith())
Use split() to extract the word before /.
Then use index() to get the position of the starting word in ref_list, and use that for the sorting key.
ordered_list = sorted(list_a, key = lambda x: ref_list.index(x.split('/')[0]))
This answer may not be the most elegant, but it works:
sorted_list = list()
for key in ref_list:
sorted_list += [sorted_value for sorted_value in list_a if \
sorted_value.startswith(key)]
I have two lists, I want to compare one list with the other and get all the close matches as output for each word.
For example:
a = ['apple','python','ice-cream']
b = ['aaple','aple','phython','icecream','cat','dog','cell']
so when I pass the list 'a' i need to get 'aaple','aple','phython','icecream' as outputs from 'b'.
I used difflib.get_close_matches(word,pattern), but couldn't pass the whole list in one of the inputs.
difflib.get_close_matches('apple',b)
OUTPUT:
['aaple','aple']
How can I pass the whole list instead of just a single word?
The following code will create a list with all the close words:
import difflib
diff_words = []
for word in a:
diff_words += difflib.get_close_matches(word, b)
print(diff_words)
You can use a nested list comprehension, such as:
[close_match for word in a for close_match in difflib.get_close_matches(word, b)]
I'm new to python so this is probably super simple.
I'm trying to iterate through a list and convert every element into uppercase. I know that this works:
word_list = ['alt', 'mach', 'time']
for i in range(0, len(word_list)):
word_list[i] = word_list[i].upper()
But I also know that you can index a list directly (not using range), but I'm not sure how to apply that to this situation. I tried this:
word_list = ['alt', 'mach', 'time']
for i in word_list:
i = i.upper()
But when I print the list afterward it hasn't changed. I suspect this is because i is changing each loop anyway and i can't just assign it to things like I'm trying to do. Is there some other way to do this while indexing the list directly?
Not really. As I think you realise, doing i = i.upper() just reassigns i to a new string, and doesn't change what's in the list.
The best you can do is to use enumerate to give you both the element and the index:
for i, word in enumerate(word_list):
word_list[i] = word.upper()
You can use list comprehensions. Example:
yourList = ["a","b","c"]
yourList = [x.upper() for x in yourList]
src: http://python-3-patterns-idioms-test.readthedocs.io/en/latest/Comprehensions.html
Super late to the party, but I recommend using the map() function.
yourList = ["a","b","c"]
fun = lambda x: x.upper()
yourList = list(map(fun, yourList))
Source: https://python-reference.readthedocs.io/en/latest/docs/functions/map.html
This question already has answers here:
Why does this iterative list-growing code give IndexError: list assignment index out of range? How can I repeatedly add (append) elements to a list?
(9 answers)
Closed 2 years ago.
m learning python from the google tutorials. am stuck on an exercise related to lists.
getting an index error
lis[j]=words.pop()[i]
IndexError: string index out of range
i need to sort the list but the words starting with x should be the first ones.
code is
def front_x(words):
i=0
lis=[]
j=0
k=0
words.sort()
while i<len(words):
if words[i][0:1]=="x":
lis[j]=words.pop()[i]
j+=1
i+=1
lis.extend(words)
while k<len(lis):
print(lis[k])
k+=1
return
lis is an empty list, any index will raise an exception.
If you wanted to add elements to that list, use lis.append() instead.
Note that you can loop over sequences directly, there is no need to keep your own counter:
def front_x(words):
lis = []
words.sort()
for word in words:
if word.startswith("x"):
lis.append(word)
for entry in lis:
print(entry)
You can reduce this further by immediately printing all words that start with x, no need to build a separate list:
def front_x(words):
for word in sorted(words):
if word.startswith("x"):
print(word)
If you wanted to sort the list with all x words coming first, use a custom sort key:
def front_x(words):
return sorted(words, key=lambda w: (not w.startswith('x'), w))
sorts the words first by the boolean flag for .startswith('x'); False is sorted before True so we negate that test, then the words themselves.
Demo:
>>> words = ['foo', 'bar', 'xbaz', 'eggs', 'xspam', 'xham']
>>> sorted(words, key=lambda w: (not w.startswith('x'), w))
['xbaz', 'xham', 'xspam', 'bar', 'eggs', 'foo']
i need to sort the list but the words starting with x should be the first ones.
Complementary to the custom search key in #Martijn's extended answer, you could also try this, which is closer to your original approach and might be easier to understand:
def front_x(words):
has_x, hasnt = [], []
for word in sorted(words):
if word.startswith('x'):
has_x.append(word)
else:
hasnt.append(word)
return has_x + hasnt
Concerning what was wrong with your original code, there are actually three problems with the line
lis[j]=words.pop()[i]
lis[j] only works if the list already has a jth element, but as you are adding items to an initially empty list, you should use lis.append(...) instead.
You want to remove the word starting with "x" at index i from the list, but pop() will always remove the last item. pop() is for stacks; never remove items from a list while looping it with an index!
You apply the [i] operator after you've popped the item from the list, i.e., you are accessing the ith letter of the word, which may be much shorter; thus the IndexError
I'm doing an exercise as following:
# B. front_x
# Given a list of strings, return a list with the strings
# in sorted order, except group all the strings that begin with 'x' first.
# e.g. ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] yields
# ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
# Hint: this can be done by making 2 lists and sorting each of them
# before combining them.
sample solution:
def front_x(words):
listX = []
listO = []
for w in words:
if w.startswith('x'):
listX.append(w)
else:
listO.append(w)
listX.sort()
listO.sort()
return listX + listO
my solution:
def front_x(words):
listX = []
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w)
listX.sort()
words.sort()
return listX + words
as I tested my solution, the result is a little weird. Here is the source code with my solution: http://dl.dropbox.com/u/559353/list1.py. You might want to try it out.
The problem is that you loop over the list and remove elements from it (modifying it):
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w)
Example:
>>> a = range(5)
>>> for i in a:
... a.remove(i)
...
>>> a
[1, 3]
This code works as follows:
Get first element, remove it.
Move to the next element. But it is not 1 anymore because we removed 0 previously and thus 1 become the new first element. The next element is therefore 2 and 1 is skipped.
Same for 3 and 4.
Two main differences:
Removing an element from a list inside loop where the list is being iterated doesn't quite work in Python. If you were using Java you would get an exception saying that you are modifying a collection that is being iterated. Python doesn't shout this error apparently. #Felix_Kling explains it quite well in his answer.
Also you are modifying the input parameter words. So the caller of your function front_x will see words modified after the execution of the function. This behaviour, unless is explicitly expected, is better to be avoided. Imagine that your program is doing something else with words. Keeping two lists as in the sample solution is a better approach.
Altering the list you're iterating over results in undefined behaviour. That's why the sample solution creates two new lists instead of deleting from the source list.
for w in words:
if w.startswith('x'):
listX.append(w)
words.remove(w) # Problem here!
See this question for a discussion on this matter. It basically boils down to list iterators iterating through the indexes of the list without going back and checking for modifications (which would be expensive!).
If you want to avoid creating a second list, you will have to perform two iterations. One to iterate over words to create listX and another to iterate over listX deleting from words.
That hint is misleading and unnecessary, you can do this without sorting and combining two lists independently:
>>> items = ['mix', 'xyz', 'apple', 'xanadu', 'aardvark']
>>> sorted(items, key=lambda item: (item[0]!='x', item))
['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
The built-in sorted() function takes an option key argument that tells it what to sort by. In this case, you want to create a tuples like (False, 'xanadu') or (True, 'apple') for each element of the original list, which you can do with a lambda.