I have two lists
x = [ None , None , "foo" , "bar" ]
y = [ "bar" , "foo" , "foo" ,"bar"]
len(x) == len(y)
I want to check if there exists an element in list x that is None then remove that element and remove corresponding element in y too .
like remove x[0] == None , so remove x[0] and y[0] from x and y
the result should be:
x = ["foo","bar"]
y = ["foo","bar"]
i tried a quite non-pythonic way which gave me a "list index out of range " error:
for i in range(0,len(x)):
if(x[i] == None):
x.remove(x[i])
y.remove(y[i])
Using the zip method you can do this very nicely:
x, y = zip(*[(e_x, e_y) for e_x, e_y in zip(x, y) if e_x is not None])
Here you iterate over both lists at once, creating a new list with tuples containing the elements of x and y. These tuples are only added if the element from x e_x is not None.
The outer zip converts the list of tuples back in two separate lists.
Edit: As Donkey Kong pointed out in a comment, it is better to use is not None instead of != None. I updated the code accordingly.
Let's call your lists xs and ys.
ys = [y for (x, y) in zip(xs, ys) if x]
xs = [x for x in xs if x]
should do the trick.
First go through and figure out what you need to remove:
remove_ix = {ix for ix, val in enumerate(x) if val is None}
Now you can use it to filter x and y:
x = [item for ix, item in enumerate(x) if ix not in remove_ix]
y = [item for ix, item in enumerate(y) if ix not in remove_ix]
Note that with your version, you'll end up skipping indices and probably having IndexErrors because if the initial length of the list is N and you remove a single item, then you'll still be looping N times, but the list is now N-1 items long. Also with list.remove, you can't guarantee that you're removing the correct item if there are duplicates (which there are in your example)
Use zip to remove items that are None (in x) from matching pairs of x and y, then use another zip(*...) to transpose the list of lists back to the references x and y:
x, y = zip(*[[ix, iy] for ix, iy in zip(x, y) if ix is not None])
I think the most performant way to achieve desired output would be dict comprehension. In that case you avoid avoid 2 list comprehension expressions:
x_list = [ None , None , "foo" , "bar" ]
y_list = [ "bar" , "foo" , "foo" ,"bar"]
d = {val:y_list[i] for i,val in enumerate(x_list) if val is not None}
new_l_y = d.values()
new_l_x = d.keys()
NOTE: You would miss order of elements but keep correspondence of items. If order matters you can use OrderedDict.
from collections import OrderedDict
d = OrderedDict((val,y_list[i]) for i,val in enumerate(x_list) if val is not None)
new_l_y = d.keys()
new_l_y = d.values()
Posting an answer in a dead thread. It might help someone.
One very neat method is to use itertool's compress method.
from itertools import compress
x = [None, None, 1, 2]
y = [5, 6, 2, 4]
y = list(compress(y, x))
x = list(compress(x, x))
Related
I have a problem in python.
I need to get differences between the two lists with sublists, but I need only comparing first element of each sublists.
Example:
Input:
x=[[1,2],[2,3],[4,5]]
y=[[1,8],[5,1]]
Output:
dif_l=[[5,1]]
Summarizing the problem, I have to subtract the x list from the y list (dif_l=y-x), but only check first element from each sublists.
Can use list comprehension:
x=[[1,2],[2,3],[4,5]]
y=[[1,8],[5,1]]
diff_l = [l for l in y if l[0] not in [k[0] for k in x]]
print(diff_l)
Use dicts as an intermediate step with the first values as keys. Return only those keys not found in the other dict.
A solution can look like this.
x=[[1,2],[2,3],[4,5]]
y=[[1,8],[5,1]]
def custom_sublist_subtract(left, right):
''' y - x should be passed as (y, x)
'''
dict_left = {item[0]: item for item in left}
dict_right = {item[0]: item for item in right}
result = [v for k, v in dict_left.items() if k not in dict_right]
return result
custom_sublist_subtract(y, x)
#Output:
[[5, 1]]
I have two lists of the same length.
The first one contains strings. The second one - strings that can be either 'True' or 'False'.
If the nth element of the second list is 'True', I want to append the nth element of the first list to another list.
So if I have:
List1:
('sth1','sth2','sth3','sth4')
List2:
('True','False','True','False')
The outcome should be List3:
('sth1','sth3').
How can I intersect two list in that way?
Use zip:
result = [x for x, y in zip(xs, ys) if y == 'True']
Example:
xs = ('sth1','sth2','sth3','sth4')
ys = ('True','False','True','False')
result = [x for x, y in zip(xs, ys) if y == 'True']
result
['sth1', 'sth3']
Or use numpy:
import numpy as np
filtered = np.array(List1)[np.array(List2)]
Btw this only works if the elements inside List2 are True/False, not if they are "True"/"False".
If you didn't know about zip :
l1 = ('sth1','sth2','sth3','sth4')
l2 = ('True','False','True','False')
l = [x for i,x in enumerate(l1) if l2[i]=='True']
print l
#=> ['sth1', 'sth3']
It would be shorter with a tuple of booleans :
l1 = ('sth1','sth2','sth3','sth4')
l2 = (True,False,True,False)
l = [x for i,x in enumerate(l1) if l2[i]]
print l
Simplest way is to use itertools.compress method as follows.
import itertools
list1 = ('sth1','sth2','sth3','sth4')
list2 = ('True','False','True','False')
list2 = map(lambda x: x == 'True', list2)
result = list(itertools.compress(list1, list2))
compress method returns an iterator, so you that is why you need to wrap the iterator object in list
I hope it helps.
I created a list of lists and then tried to get a distinct list of the lists using set(), but it appears as though i cant use list on a set.
Is there another way to accomplish this with a concise statement that performs well?
CODE
x = [1,2]
y = [1,2]
z = [2,3]
xyz = []
xyz.append(x)
xyz.append(y)
xyz.append(z)
set(xyz)
Error
TypeError: unhashable type: 'list'
Goal
xyz = [[1,2],[2,3]]
if you want to preserve order and keep your lists, you could use generator function to remove the dupes from your list:
xyz = [x, y, z]
def remove_dupe_subs(l):
seen = set()
for sub in l:
tup = tuple(sub)
if tup not in seen:
yield sub
seen.add(tup)
xyz[:] = remove_dupe_subs(xyz)
Or using a generator expression taking advantage of the fact set.add returns None :
seen = set()
xyz[:] = (seen.add(tup) or sub for sub, tup in zip(xyz, map(tuple, xyz)) if tup not in seen)
print(xyz)
If the list members are hashable, it will work
x = [1,2]
y = [1,2]
z = [2,3]
xyz = []
xyz.append(tuple(x))
xyz.append(tuple(y))
xyz.append(tuple(z))
print xyz
xyz_set = set(xyz)
print xyz_set
It's a little bit convoluted, but this will do the trick in a single line:
xyz=[list(x) for x in list(set((tuple(x),tuple(y),tuple(z))))]
Lets say I have a list of tuples as follows
l = [(4,1), (5,1), (3,2), (7,1), (6,0)]
I would like to iterate over the items where the 2nd element in the tuple is 1?
I can do it using an if condition in the loop, but I was hoping there will a be amore pythonic way of doing it?
Thanks
You can use a list comprehension:
[ x for x in l if x[1] == 1 ]
You can iterate over tuples using generator syntax as well:
for tup in ( x for x in l if x[1] == 1 ):
...
How about
ones = [(x, y) for x, y in l if y == 1]
or
ones = filter(lambda x: x[1] == 1, l)
Just use the if. It's clear and simple.
for x, y in tuples:
if y == 1:
do_whatever_with(x)
Build a generator over it:
has_1 = (tup for tup in l if l[1] == 1)
for item in has_1:
pass
for e in filter(l, lambda x: x[1] == 1):
print e
Try this, using list comprehensions is the pythonic way to solve the problem:
lst = [(4,1), (5,1), (3,2), (7,1), (6,0)]
[(x, y) for x, y in lst if y == 1]
=> [(4, 1), (5, 1), (7, 1)]
Notice how we use tuple unpacking x, y to obtain each of the elements in the pair, and how the condition if y == 1 filters out only those element with value 1 in the second element of the pair. After that, you can do anything you want with the elements found, in particular, I'm reconstructing the original pair in this part at the left: (x, y)
Since you want to iterate, itertools.ifilter is a nice solution:
from itertools import ifilter
iter = ifilter(lambda x: x[1] == 1, l)
for item in iter:
pass
All,
o1 = ["a","b","c","d","e","f","g","h"]
index = [3,4]
value = ["c","d"]
[x for x in o1 if x not in value]
[x for x in o1 if x not in [o1[y] for y in index]]
any simpler solution for above lc?
Thanks
(x for x in o1 if x not in value)
(x for i, x in enumerate( o1 ) if i not in index )
Note that using generator expressions will save you a pass through the list, and using sets instead of lists for index and value will be more efficient.