Double for statement in list comprehension - string

wordlist = ['cat','dog','rabbit']
letterlist = [ ]
To list all the characters in all the words, we can do this:
letterlist = [word[i] for word in wordlist for i in range(len(word))]
['c', 'a', 't', 'd', 'o', 'g', 'r', 'a', 'b', 'b', 'i', 't']
However, when I try to do it in this way:
letterlist = [character for character in word for word in wordlist]
I get the error:
NameError: name 'word' is not defined on line 9
Can someone explain my error in understanding how list comprehension works?
Thanks.

Writing
wordlist = ["cat", "dog", "rabbit"]
letterlist = [character for character in word for word in wordlist]
is comparable to the following nested loop:
wordlist = ["cat", "dog", "rabbit"]
letterlist = []
for character in word:
for word in wordlist:
letterlist.append(character)
This loop will throw the same error as your list comprehension because you are attempting to reference character in word before defining word as an element of wordlist. You just have the order backwards. Try the following:
letterlist = [character for word in wordlist for character in word]

Related

Is there a way to split strings inside a list?

I am trying to split strings inside a list but I could not find any solution on the internet. This is a sample, but it should help you guys understand my problem.
array=['a','b;','c','d)','void','plasma']
for i in array:
print(i.split())
My desired output should look like this:
output: ['a','b',';','c','d',')','void','plasma']
One approach uses re.findall on each starting list term along with a list comprehension to flatten the resulting 2D list:
inp = ['a', 'b;', 'c', 'd)', 'void', 'plasma']
output = [j for sub in [re.findall(r'\w+|\W+', x) for x in inp] for j in sub]
print(output) # ['a', 'b', ';', 'c', 'd', ')', 'void', 'plasma']

Any reason not to convert string to list this way?

I'm using PyCharm on Windows (and very new to Python)
I'm a 'what happens when I try this?' person and so I tried:
alist = []
alist += 'wowser'
which returns ['w', 'o', 'w', 's', 'e', 'r']
Is there any reason not to convert a string to a list of individual characters like this? I know I could use For loop method OR I could .append or +concatenate (both seem to be too tedious!!), but I can't find anything that mentions using += to do this. So, since I'm new, I figure I should ask why not to do it this way before I develop a bad habit that will get me into trouble in the future.
Thanks for your help!
I think this would help: Why does += behave unexpectedly on lists?
About the question "Is there any reason not to convert a string to a list of individual characters like this". I think it depends on your purpose. It will be quite convenient if you need to split the letters. If you don't want to split the letters, just don't use it.
String is a type of array so it behaves like an array as lists do.
>>> # This way you would do it with a list:
>>> list('wowser')
['w', 'o', 'w', 's', 'e', 'r']
>>> lst=list('wowser')
>>> a='w'
>>> a is lst[0]
True
>>> # The String Version:
>>> strng = 'wowser'
>>> a is strng[0]
True
>>> # Iterate over the string like doing it with lists:
>>> [print(char) for char in 'wowser']
w
o
w
s
e
r
>>> [print(char) for char in ['w', 'o', 'w', 's', 'e', 'r']]
w
o
w
s
e
r
w3schools.com
docs.python.org

I want to be able to go through a list, and sort every letter in every word to least common to most common

I am making a program that guesses your word, so it asks if a certain letter is in it, it would be most effective if I knew what letter was most common so the program can ask the least amount of questions.
for example:
if my list is ["apple", "tree", "paper"]
it must print out:
["e", "p", "a", "r",...
(because p and a are most common they at the front of
the list, and "t" would be at the back of the list because it only occurs once)
And if it would help; every word in the list has die same length.
Use Counter for counting.
from collections import Counter
l = ["apple", "tree", "paper"]
[element for element, frequency in Counter(''.join(l)).most_common()]
# => ['p', 'e', 'a', 'r', 'l', 't']
Use a collections.Counter:
import collections
...
lst = ["apple", "tree", "paper"]
counter = collections.Counter(''.join(lst))
print(counter.most_common())
# [('p', 4), ('e', 4), ('a', 2), ('r', 2), ('l', 1), ('t', 1)]
print([t[0] for t in counter.most_common()])
# ['p', 'e', 'a', 'r', 'l', 't']
If you want it to be case insensitive convert the strong to lower case and use.
for your purpose, you can use the counter in python collections which will be effective. below is the code sample.
from collections import Counter
words = ["apple", "tree", "paper"]
cnt = Counter()
for word in words:
word = word.lower() #incase u want it case insensitive
for letter in word:
cnt[letter]+=1
print(cnt)
finally convert the counter to dictionary if needed
count_dict = dict(cnt)

Based on a condition perform reranking of elements in the list in python

i have a ranked list of elements as below :
ranked_list_1 = ['G','A','M','S','D']
i need to rerank the list as below
1) Re rank as :
re_ranked_list_1 = ['A','M','D','E','G','S']
Logic : 'G' and 'S' should always be in last 2 positions and new element 'E' should also be tagged to the list just before the last 2 position.
I think this is what you want. This will put 'G' and 'S' at the end, in the order they appear in the list.
ordered_list = list()
final_terms = ['E']
for item in ranked_list_1:
if item in ['G', 'S']:
final_terms.append(item)
else:
ordered_list.append(item)
output_list = ordered_list + final_terms
print(output_list)
>>>['A', 'M', 'D', 'E', 'G', 'S']

convert a list of lists to a list of string

I have a list of lists like this
list1 = [['I am a student'], ['I come from China'], ['I study computer science']]
len(list1) = 3
Now I would like to convert it into a list of string like this
list2 = ['I', 'am', 'a', 'student','I', 'come', 'from', 'China', 'I','study','computer','science']
len(list2) = 12
I am aware that I could conversion in this way
new_list = [','.join(x) for x in list1]
But it returns
['I,am,a,student','I,come,from,China','I,study,computer,science']
len(new_list) = 3
I also tried this
new_list = [''.join(x for x in list1)]
but it gives the following error
TypeError: sequence item 0: expected str instance, list found
How can I extract each word in the sublist of list1 and convert it into a list of string? I'm using python 3 in windows 7.
Following your edit, I think the most transparent approach is now the one that was adopted by another answer (an answer which has since been deleted, I think). I've added some whitespace to make it easier to understand what's going on:
list1 = [['I am a student'], ['I come from China'], ['I study computer science']]
list2 = [
word
for sublist in list1
for sentence in sublist
for word in sentence.split()
]
print(list2)
Prints:
['I', 'am', 'a', 'student', 'I', 'come', 'from', 'China', 'I', 'study', 'computer', 'science']
Given a list of lists where each sublist contain strings this could be solved using jez's strategy like:
list2 = ' '.join([' '.join(strings) for strings in list1]).split()
Where the list comprehension transforms list1 to a list of strings:
>>> [' '.join(strings) for strings in list1]
['I am a student', 'I come from China', 'I study computer science']
The join will then create a string from the strings and split will create a list split on spaces.
If the sublists only contain single strings, you could simplify the list comprehension:
list2 = ' '.join([l[0] for l in list1]).split()

Resources