python list different way than googles solution - python

I am working on the exercises for python from Google and I can't figure out why I am not getting the correct answer for a list problem. I saw the solution and they did it differently then me but I think the way I did it should work also.
# 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.
def front_x(words):
# +++your code here+++
list = []
xlist = []
for word in words:
list.append(word)
list.sort()
for s in list:
if s.startswith('x'):
xlist.append(s)
list.remove(s)
return xlist+list
The call is:
front_x(['bbb', 'ccc', 'axx', 'xzz', 'xaa'])
I get:
['xaa', 'axx', 'bbb', 'ccc', 'xzz']
when the answer should be:
['xaa', 'xzz', 'axx', 'b
bb', 'ccc']
I've don't understand why my solution does not work
Thank you.

You shouldn't modify a list while iterating over it. See the for statement documentation.
for s in list:
if s.startswith('x'):
xlist.append(s)
list.remove(s) # this line causes the bug

Try this:
def front_x(words):
lst = []
xlst = []
for word in words:
if word.startswith('x'):
xlst.append(word)
else:
lst.append(word)
return sorted(xlst)+sorted(lst)
>>> front_x(['bbb', 'ccc', 'axx', 'xzz', 'xaa'])
['xaa', 'xzz', 'axx', 'bbb', 'ccc']

Related

Split The Second String of Every Element in a List into Multiple Strings

I am very very new to python so I'm still figuring out the basics.
I have a nested list with each element containing two strings like so:
mylist = [['Wowza', 'Here is a string'],['omg', 'yet another string']]
I would like to iterate through each element in mylist, and split the second string into multiple strings so it looks like:
mylist = [['wowza', 'Here', 'is', 'a', 'string'],['omg', 'yet', 'another', 'string']]
I have tried so many things, such as unzipping and
for elem in mylist:
mylist.append(elem)
NewList = [item[1].split(' ') for item in mylist]
print(NewList)
and even
for elem in mylist:
NewList = ' '.join(elem)
def Convert(string):
li = list(string.split(' '))
return li
print(Convert(NewList))
Which just gives me a variable that contains a bunch of lists
I know I'm way over complicating this, so any advice would be greatly appreciated
You can use list comprehension
mylist = [['Wowza', 'Here is a string'],['omg', 'yet another string']]
req_list = [[i[0]]+ i[1].split() for i in mylist]
# [['Wowza', 'Here', 'is', 'a', 'string'], ['omg', 'yet', 'another', 'string']]
I agree with #DeepakTripathi's list comprehension suggestion (+1) but I would structure it more descriptively:
>>> mylist = [['Wowza', 'Here is a string'], ['omg', 'yet another string']]
>>> newList = [[tag, *words.split()] for (tag, words) in mylist]
>>> print(newList)
[['Wowza', 'Here', 'is', 'a', 'string'], ['omg', 'yet', 'another', 'string']]
>>>
You can use the + operator on lists to combine them:
a = ['hi', 'multiple words here']
b = []
for i in a:
b += i.split()

Creating one list by combining two list in a list comprehension

new to Python. Tried to find an answer but couldn't find anything or understand anything. I'm ok with for loops but I'm trying to combine two lists into one through a list comprehension. I'm fairly new to list comprehensions. So Something like:
list1 = ['a','b','c']
list2 = ['p','q','r','s','t','u']
I want an output that comes out like this:
list3 = ['ap','aq','ar','as','at','au','bp','bq','br','bs','bt','bu','cp','cq','cr','cs','ct','cu'...]
I didn't write the whole thing but I hope it gets the point across. How can I do this based solely on a list comprehension?
You can try
list1 = ['a','b','c']
list2 = ['p','q','r','s','t','u']
result = [ a+b for a in list1 for b in list2 ]
You can use itertools.product() to generate the desired output:
from itertools import product
[''.join(item) for item in product(list1, list2)]
This outputs:
['ap', 'aq', 'ar', 'as', 'at', 'au', 'bp', 'bq', 'br', 'bs', 'bt', 'bu', 'cp', 'cq', 'cr', 'cs', 'ct', 'cu']
Prefer this answer over ones that use multiple for clauses in a single list comprehension: some consider it to be poor style.

Python: for-in loop is not checking the last string in a list, why?

I'm using a for-in loop to remove any strings from a list titled "words" that start with "x" as part of a function, but find that this loop will not check the last string in the list. Why is this?
After adding some print statements to figure out where things were going wrong I narrowed it down to the second for-in loop, but beyond that I'm not sure what to do...
def front_x(words):
print '\n'
words.sort()
print words
words2 = []
for string in words:
if string[0] == 'x':
words2.append(string)
#print 'added ' + string + ' to words2'
#else:
#print '(append)checked ' + string
for string in words:
if string[0] == 'x':
words.remove(string)
print 'removed ' + string
else: print 'checked ' + string
words2.extend(words)
return words2
As you can see, in each case it will check all of the elements in the list printed above except for the last. Below that are what my program got vs what it is supposed to get.
['axx', 'bbb', 'ccc', 'xaa', 'xzz']
checked axx
checked bbb
checked ccc
removed xaa
X got: ['xaa', 'xzz', 'axx', 'bbb', 'ccc', 'xzz']
expected: ['xaa', 'xzz', 'axx', 'bbb', 'ccc']
['aaa', 'bbb', 'ccc', 'xaa', 'xcc']
checked aaa
checked bbb
checked ccc
removed xaa
X got: ['xaa', 'xcc', 'aaa', 'bbb', 'ccc', 'xcc']
expected: ['xaa', 'xcc', 'aaa', 'bbb', 'ccc']
['aardvark', 'apple', 'mix', 'xanadu', 'xyz']
checked aardvark
checked apple
checked mix
removed xanadu
X got: ['xanadu', 'xyz', 'aardvark', 'apple', 'mix', 'xyz']
expected: ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
You are mutating the list as you are iterating over it. Behind the scenes Python is stepping through the numeric index of each item in the list. When you remove an item, all of the items with a higher index are shifted.
Instead, build an list of the indices you want to remove, then remove them. Or use a list comprehension to build a new list.
def front_x(words):
words2 = [w for w in words if w.startswith('x')]
return words2
If you want to also mutate the original list (modify words) with the function you can do so using:
def drop_front_x(words):
words2 = []
indices = [i for i, w in enumerate(words) if w.startswith('x')]
for ix in reversed(indices):
words2.insert(0, words.pop(ix))
return words2
I think you need this to get a list as you expected result looks like:
not_xes = [i for i in words if not i.startswith('x')]
xes = [i for i in words if i.startswitch('x')]
expected_result = xes + not_xes

Replace duplicates in a list column

I got a list, in one (the last) column is a string of comma separated items:
temp = ['AAA', 'BBB', 'CCC-DDD', 'EE,FFF,FFF,EE']
Now I want to remove the duplicates in that column.
I tried to make a list out of every column:
e = [s.split(',') for s in temp]
print e
Which gave me:
[['AAA'], ['BBB'], ['CCC-DDD'], ['EE', 'FFF', 'FFF', 'EE']]
Now I tried to remove the duplicates with:
y = list(set(e))
print y
What ended up in an error
TypeError: unhashable type: 'list'
I'd appreciate any help.
Edit:
I didn't exactly said what the end result should be. The list should look like that
temp = ['AAA', 'BBB', 'CCC-DDD', 'EE', 'FFF']
Just the duplicates should get removed in the last column.
Apply set on the elements of the list not on the list of lists. You want your set to contain the strings of each list, not the lists.
e = [list(set(x)) for x in e]
You can do it directly as well:
e = [list(set(s.split(','))) for s in temp]
>>> e
[['AAA'], ['BBB'], ['CCC-DDD'], ['EE', 'FFF']]
you may want sorted(set(s.split(','))) instead to ensure lexicographic order (sets aren't ordered, even in python 3.7)
for a flat, ordered list, create a flat set comprehension and sort it:
e = sorted({x for s in temp for x in s.split(',')})
result:
['AAA', 'BBB', 'CCC-DDD', 'EE', 'FFF']
Here is solution, that uses itertools.chain method
import itertools
temp = ['AAA', 'BBB', 'CCC-DDD', 'EE,FFF,FFF,EE']
y = list(set(itertools.chain(*[s.split(',') for s in temp])))
# ['EE', 'FFF', 'AAA', 'BBB', 'CCC-DDD']
a = ['AAA', 'BBB', 'CCC-DDD', 'EE,FFF,FFF,EE']
b = [s.split(',') for s in a]
c = []
for i in b:
c = c + i
c = list(set(c))
['EE', 'FFF', 'AAA', 'BBB', 'CCC-DDD']
Here is a pure functional way to do it in Python:
from functools import partial
split = partial(str.split, sep=',')
list(map(list, map(set, (map(split, temp)))))
[['AAA'], ['BBB'], ['CCC-DDD'], ['EE', 'FFF']]
Or as I see the answer doesn't need lists inside of a list:
from itertools import chain
list(chain(*map(set, (map(split, temp)))))
['AAA', 'BBB', 'CCC-DDD', 'EE', 'FFF']

Need to sort given strings (Strings starting with x first)

Code doesn't return last word when given ['mix', 'xyz', 'apple', 'xanadu', 'aardvark'] list.
def front_x(words):
x_list = []
no_x_list = []
[x_list.append(i) for i in words if i[0] == "x"]
[no_x_list.append(words[i2]) for i2 in range(len(words)-1) if words[i2] not in x_list]
x_list.sort()
no_x_list.sort()
return x_list + no_x_list
print front_x(['mix', 'xyz', 'apple', 'xanadu', 'aardvark'])
Must be:
['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
With lists ['bbb', 'ccc', 'axx', 'xzz', 'xaa'] and ['ccc', 'bbb', 'aaa', 'xcc', 'xaa'] everything is right ['xaa', 'xzz', 'axx', 'bbb', 'ccc'] and ['xaa', 'xcc', 'aaa', 'bbb', 'ccc']
Iterating on range(len(words)-1) looks incorrect. More so, making list appends with list comprehension is quite unpythonic; list comps are for building lists not making making list appends which is rather ironic here.
You can perform the sort once by sorting based on a two-tuple whose fist item checks if a word startswith 'x' and puts those ahead. The second item in the tuple applies a lexicograhical sort on the list, breaking ties:
def front_x(words):
return sorted(words, key=lambda y: (not y.startswith('x'), y))
print front_x(['mix', 'xyz', 'apple', 'xanadu', 'aardvark'])
# ['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
Just remove the -1 from range(len(words)-1)
This will be the minimal change in your code.
You can try this:
words = ['mix', 'xyz', 'apple', 'xanadu', 'aardvark']
new_words = [i for i in words if i[0].lower() == "x"]
words = [i for i in words if i[0].lower() != "x"]
final_words = sorted(new_words)+sorted(words)
print(final_words)
Output:
['xanadu', 'xyz', 'aardvark', 'apple', 'mix']
You have to use len(words) instead of len(words)-1 to get expected output.
So, try this way :
def front_x(words):
x_list = []
no_x_list = []
[x_list.append(i) for i in words if i[0] == "x"]
[no_x_list.append(words[i2]) for i2 in range(len(words)) if words[i2] not in x_list]
x_list.sort()
no_x_list.sort()
return x_list + no_x_list
print front_x(['mix', 'xyz', 'apple', 'xanadu', 'aardvark'])
Output :
['xanadu', 'xyz', 'aardvark', 'apple', 'mix']

Categories