List comprehension on lists within lists - python

If I create two lists that contain lists like this:
bad_list.append(['blue_widget', 'cracked', '776'])
bad_list.append(['red_widget', 'not_smooth', '545'])
bad_list.append(['yellow_widget', 'spots', '35'])
bad_list.append(['green_widget', 'smells_bad', '10'])
bad_list.append(['purple_widget', 'not_really_purple', '10'])
good_list.append(['blue_widget', 'ok', '776'])
good_list.append(['red_widget', 'ok', '545'])
good_list.append(['green_widget', 'ok', '10'])
I would love to be able to use list comprehension to compare the two lists and remove
all items in the bad list that are present in the good list using the first element
(x_widget) as item to compare. Using the example above I should be left with:
['yellow_widget', 'spots', '35']
['purple_widget', 'not_really_purple', '10']
I have tried using list comprehension and it works but the new list does not retain each line:
final_list = [x for x in bad_list[0] if x not in good_list[0]]
When I print out the contents using for item in final_list I get something like:
yellow_widget
smells_bad
10
Any clues would be much appreciated.

One liner
[x for x in bad_list if any(x[0] == y[0] for y in good_list)]
*thanks #Bakuriu

Not really optimized by any means, but this should work: http://codecube.io/AD7RHA
bad_list=[]
good_list=[]
bad_list.append(['blue_widget', 'cracked', '776'])
bad_list.append(['red_widget', 'not_smooth', '545'])
bad_list.append(['yellow_widget', 'spots', '35'])
bad_list.append(['green_widget', 'smells_bad', '10'])
bad_list.append(['purple_widget', 'not_really_purple', '10'])
good_list.append(['blue_widget', 'ok', '776'])
good_list.append(['red_widget', 'ok', '545'])
good_list.append(['green_widget', 'ok', '10'])
# ['yellow_widget', 'spots', '35']
# ['purple_widget', 'not_really_purple', '10']
labels = zip(*good_list)[0]
new_bad_list=[]
for item in bad_list:
if item[0] not in labels:
new_bad_list.append(item)
print new_bad_list
or this one-liner:
new_bad_list=[item for item in bad_list if item[0] not in zip(*good_list)[0]]

Try This:
print [ele for ele in bad_list if ele[0] not in [i[0] for i in good_list]]
Output:
[['yellow_widget', 'spots', '35'], ['purple_widget', 'not_really_purple', '10']]

There is a more efficient solution. Make a set from your list
bad_set = set(bad_list)
good_set = set(good_list)
Now to remove all items in the bad list that are present in the good list, you can simple substract the sets:
bad_set - good_set
Convert set back to list if you like.

the simplest way is:
final_list = [x for x in bad_list if x[0] not in [x[0] for x in good_list]]
but notice that to test an element's existing in a list is not that efficient.
So, you can first build a set:
good_list_names = set([x[0] for x in good_list])
and then:
final_list = [x for x in bad_list if x[0] not in good_list_names]

Related

Del list and next list element in list if string exist

I have an example:
list = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
for i in range(len(list)):
if list[i][-1] == "last":
del(list[i+1])
del(list[i])
I'd like to delete this list where the last item is "last" and the next item on the list.
In this example there is a problem every time - I tried different configurations, replacing with numpy array - nothing helps.
Trackback:
IndexError: list index out of range
I want the final result of this list to be ['3', '4', 'next']
Give me some tips or help how I can solve it.
Try this:
l = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
delete_next = False
to_ret = []
for x in l:
if x[-1] == 'last':
delete_next = True
elif delete_next:
delete_next = False
else:
to_ret.append(x)
Using a variable to store if this needs to be deleted
Loop over the list, if the last element of that iteration == 'last' then skip, else, append to a new list.
Also, it is not recommended to edit lists while iterating over them as strange things can happen, as mentioned in the comments above, like the indexes changing.
l = [['2 a', 'nnn', 'xxxx','last'], ['next, next'], ['3', '4', 'next']]
newlist = []
for i in l:
if i[-1] == 'last':
continue
else:
newlist.append(i)

how to add a item in a list of list using python

Is there any way to add a item to a list of list using python.
As an example there is a list as below:
test_list = [['abc','2'],['cds','333'],['efg']]
I want to add a item '444' for the position test_list[2][1].
At last list should be:
test_list = [['abc','2'],['cds','333'],['efg','444']]
Yes that is definitely something you can do.
You simply access the list object that you want to add another item to by its index, and then call .append() on that list object with the new value.
test_list = [['abc','2'], ['cds','333'], ['efg']]
test_list[2].append('444')
# test_list is now: [['abc','2'], ['cds','333'], ['efg', '444']]
test_list = [['abc','2'],['cds','333'],['efg']]
test_list[2].insert(1,"444")
print(test_list)
Try using append, append does your job:
>>> test_list = [['abc','2'],['cds','333'],['efg']]
>>> test_list[2].append('444')
>>> test_list
[['abc', '2'], ['cds', '333'], ['efg', '444']]
>>>
Or use +=, that adds stuff together, but two lists, so do:
>>> test_list = [['abc','2'],['cds','333'],['efg']]
>>> test_list[2] += ['444']
>>> test_list
[['abc', '2'], ['cds', '333'], ['efg', '444']]
>>>
append is a builtin python list method, here is the documentation for it, and for +=, that is a builtin addition operator, see the documentation for it.
Above Three are absolutely correct. But I want to add One thing If you want to add an element in a list of list and you don't know the ending index you can do something like,
>>> test_list = [['abc','2'],['cds','333'],['efg']]
>>> test_list[-1].append('444')
>>> test_list
[['abc', '2'], ['cds', '333'], ['efg', '444']]
you can also use cutting to do this:
test_list = [['abc', '2'], ['cds', '333'], ['efg']]
test_list[2][1:] = ['444']
print(test_list)
[['abc', '2'], ['cds', '333'], ['efg', '444']]

How to check type of an element in python list

1) I have this list in python.
my_list = ['9', 'sam', 'USA', '25']
How to get only the numbers from this list? I want to filter only the numbers.
2) And, if I have something like this. How to get only the number? Not using the substrings or whatever. Because the text is dynamic. Is there a way to get only numbers from a text in python?
text = "I am 28 years old."`
Here's a useful list comprehension:
>>> [item for item in my_list if item.isnumeric()]
['9', '25']
Suggested Readings:
String methods
Use this:
my_list = ['9', 'sam', 'USA', '25']
[item for item in my_list if item.isdigit()]
For your second question:
import re
re.findall("[0-9]+",text)

Python - removing items in multidimensional array

I have a multidimensional array such as this:
[["asdf","bmnl", "123","456,"0","999","1234","3456"],["qwer","tyui","789","657,"122","9","673","1"]]
However, in the multidimensional array, only the last 6items of each array are needed and the first two are not needed. How can I remove the first two pieces of data from each of the arrays within the multidimensional array so it would look like:
[["123","456,"0","999","1234","3456"],["789","657,"122","9","673","1"]]
So far, I have done this:
list1 = []
list2 = []
for row in rows:
list1.append(row[0].split(',')) #to put the split list into the top i i.e. [["asdf","bmnl", "123","456,"0","999","1234","3456"]["qwer","tyui","789","657,"122","9","673","1"]]
for i in list1:
for index in len(list1):
if index >=2:
list2.append(index) #this does not work and causes errors
How could I go about fixing this so the output would be:
[["123","456,"0","999","1234","3456"],["789","657,"122","9","673","1"]]
Thanks
Just use a list comprehension and grab every element from index 2 and beyond in each sublist:
>>> array = [["asdf","bmnl", "123","456","0","999","1234","3456"],["qwer","tyui","789","657","122","9","673","1"]]
>>> [sublist[2:] for sublist in array]
[['123', '456', '0', '999', '1234', '3456'], ['789', '657', '122', '9', '673', '1']]
lst = [["asdf","bmnl", "123","456","0","999","1234","3456"],["qwer","tyui","789","657","122","9","673","1"]]
for i in lst:
del i[0:2] #deleting 0 and 1 index from each list
print lst
This is a typical use case for a list comprehension:
list2 = [item[2:] for item in list1]
You can use a list comprehension like below:
[item[2:] for item in my_list]
item[2:] called list slicing, and it means that for each sub-list of my_list, we take items from the index 2 till the last item.
Output:
>>> my_list = [["asdf", "bmnl", "123", "456", "0", "999", "1234", "3456"], ["qwer", "tyui", "789", "657", "122", "9", "673", "1"]]
>>>
>>> [item[2:] for item in my_list]
[['123', '456', '0', '999', '1234', '3456'], ['789', '657', '122', '9', '673', '1']]
start = [["asdf","bmnl", "123","456","0","999","1234","3456"],
["qwer","tyui","789","657","122","9","673","1"]]
list_1, list_2 = [i[2:] for i in start] # I use list comprehension to create a multidimensional
# list that contains slices of each object in the base
# list and unwrap it to list_1 and list_2
Same as
n_list = [] #create an empty new list
for i in start: #loop through the origional
n_list.append(i[2:]) #append slices of each item to the new list
list_1, list_2 = n_list #unwrap the list

Find matching items in nested list

I'm trying to match a list of items to another list of items of a different dimension and print an element from the second list if the item is matched. For example:
stlist=['6', '3', '4', '2', '5', '1']
ndlist=[['Tom', '1'], ['Joh', '2'], ['Sam', '3'], ['Tommy','4'], ['Nanni', '5'], ['Ron', '6']]
My outputlist is producing the names in the ascending order of my stlist.
i.e Tom, Joh, Sam, Tommy, Nanni, Ron but I want the outputlist to be in the same order as the stlist.
My Python code is:
for sublist in ndlist:
for element in stlist:
if element in sublist[1]:
print(sublist[0])
The outputlist displayed from the above codes is: Tom, Joh, Sam, Tommy, Nanni, Ron instead of
outputlist = [Ron, Sam, Tommy, Joh, Nanni, Tom]
So it's actually sorting in ascending order my 1stlist and printing the names from the 2ndlist in that order.But if my stlist was in ascending order the outputlist would be fine.
Can anyone tell me why please and how should I modify the codes to get my desired outputlist.
Try to rearrange your for loops:
for element in stlist:
for sublist in ndlist:
if element in sublist[1]:
print (sublist[0])
Also, the if statement should maybe be like this: if element == sublist[1]: or else the element '1' would be found in some ndlist element like this one: ['foo', '10']
Furthermore, this solution is not the most efficient with large lists. To make it more efficient you could try something like sorting the ndlist and performing binary search to check if an element exists.
You could use sorted and a custom sort key (a Lambda function) to do this:
>>> [i[0] for i in sorted(ndlist, key = lambda x:stlist.index(x[1]))]
['Ron', 'Sam', 'Tommy', 'Joh', 'Nanni', 'Tom']
This line of code sorts ndlist using the position of the numbers in stlist as the sort key, then a list comprehension builds a new list containing only the names.
Instead of nesting loops or sorting you could also create a mapping with one linear run through ndlist and then use another linear run through stlist to build the result list:
mapping = dict((b, a) for a, b in ndlist)
result = [mapping[x] for x in stlist]
print(result)

Categories