Reputation: 97
I want to filter a nested list by another list which can be of variable length. If any item of a sublist matches any element of the filter list, the sublist should be excluded. The following code works for me but is there a "cleaner" solution for this task?
the_list = [['blue'], ['blue', 'red', 'black'], ['green', 'yellow'], ['yellow', 'green'], ['orange'], ['white', 'gray']]
filters = ['blue', 'white']
filtered_list = []
for sublist in the_list:
for item in sublist:
if item in filters:
break
filtered_list.append(sublist)
break
Expected output:
filtered_list = [['green', 'yellow'], ['yellow', 'green'], ['orange']]
Upvotes: 8
Views: 11407
Reputation: 21
this is pretty close to what you have
the_list = [['blue'], ['blue', 'red', 'black'], ['green', 'yellow'],
['yellow', 'green'], ['orange'], ['white', 'gray']]
filters = ['blue', 'white']
filtered_list = []
for sublist in the_list:
sub_filtered_list=[]
for item in sublist:
if item in filters:
continue
else:
sub_filtered_list.extend([item])
if sub_filtered_list==[]:
continue
else:
filtered_list.append(sub_filtered_list)
print(filtered_list)
Upvotes: 2
Reputation: 23753
Using sets.
the_list = map(set, the_list)
filters = set(filters)
fl = []
for sub in the_list:
sub = sub.difference(filters)
if sub:
fl.append(list(sub))
Upvotes: 3
Reputation: 674
filtered_list=[];
for sublist in the_list:
if len(list(set(sublist).intersection(filters_exclude)))>0:
break;
filtered_list.append(sublist);
set(sublist).intersection(filters_exclude) returns the intersection of both the lists. List() converts the set into List. Len() returns the length of the List.
Upvotes: 1
Reputation: 26315
You can also filter()
out lists that don't have an intersection with the list filters
, using Set intersection
:
>>> the_list = [['blue'], ['blue', 'red', 'black'], ['green', 'yellow'], ['yellow', 'green'], ['orange'], ['white', 'gray']]
>>> filters = ['blue', 'white']
>>> list(filter(lambda x: not set(x).intersection(filters), the_list))
[['green', 'yellow'], ['yellow', 'green'], ['orange']]
Or with a comprehension:
>>> [x for x in the_list if not set(x).intersection(filters)]
[['green', 'yellow'], ['yellow', 'green'], ['orange']]
Upvotes: 3
Reputation: 71451
You can use list comprehension:
the_list = [['blue'], ['blue', 'red', 'black'], ['green', 'yellow'],['orange'], ['white', 'gray']]
filters = ['blue', 'white']
final_l = [i for i in the_list if not any(b in filters for b in i)]
Output:
[['green', 'yellow'], ['orange']]
Or, using filter:
final_l = filter(lambda x:not any(b in filters for b in x), the_list)
Upvotes: 4
Reputation: 109546
You can use a conditional list comprehension.
>>> [sublist for sublist in the_list
if all(filter not in set(sublist) for filter in filters)]
[['green', 'yellow'], ['orange']]
Upvotes: 3
Reputation: 1744
You can use filter
and map
to make this a "one-liner". It doesn't improve readability, but it works:
filters_exclude = [2, 4]
initial_list = [[1, 2, 3, 4], [1, 2, 3], [2, 3, 4, 5]]
final = list(map(lambda x: filter(lambda y: y not in filters_exclude, x), initial_list)
Example:
>>> filters_exclude = [2, 4]
>>> map(lambda x: filter(lambda y: y not in filters_exclude, x), [[1, 2, 3, 4], [1, 2, 3]])
[[1, 3], [1, 3]]
Upvotes: 3
Reputation: 40941
Perhaps a bit more semantic would be to use any
.
for sublist in the_list:
if any(item in filters_exclude for item in sublist):
continue
filtered_list.append(sublist)
Maybe overkill, but you could even factor that into its own function then use the builtin filter
def good_list(some_list):
return not any(item in filters_exclude for item in some_list)
filtered_list = filter(good_list, the_list)
This should accomplish the goal you described. However, the code you wrote has potential issues, as mentioend in the comments.
Upvotes: 5