Reputation: 970
I have a list of tuples like so:
a = [('1', '2', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '4', '5', 'w', 'w', 'w', 'w'),
('1', '4', '4', '4', 'w', 'w', 'w', 'w'),
('1', '5', '5', '5', 'w', 'w', 'w', 'w')]
I want to be able to filter out the tuples that contain certain items. For example, I want to find all the tuples that contain '5', '5', 'w', 'w', 'w', 'w'
specifically and place them in a list.
filter_for = ['5', '5', 'w', 'w', 'w', 'w']
Expected result would be:
result = [('1', '2', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '5', '5', 'w', 'w', 'w', 'w')]
filter_for
will have a varying length of 1 to 7 so I using and
is not going to be ideal.
I've tried using
[i for i in a if all(j in filtered_for for j in a)]
but that doesn't work.
EDIT: If ('1', '5', '5', '5', 'w', 'w', 'w', 'w')
was also in the list I wouldn't want that tuple to be found. I guess I didn't specify this as all working solutions below would return this tuple as well.
Upvotes: 0
Views: 2807
Reputation: 134
This code seems to work, it tests every list by dividing them in several lists of the same length as filter_for
Edit: I tried to add some excluded patterns after your edit
a = [('1', '2', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '4', '5', 'w', 'w', 'w', 'w'),
('1', '4', '4', '4', 'w', 'w', 'w', 'w'),
('1', '5', '5', '5', 'w', 'w', 'w', 'w')]
filter_for = ['5', '5', 'w', 'w', 'w', 'w']
excluded = [('1', '5', '5', '5', 'w', 'w', 'w', 'w')]
# add a padding key to excluded patterns
for x in range(len(excluded)):
value = excluded[x]
excl = {'value': value}
for i in range(len(value) - len(filter_for) + 1):
if list(value[i:i+len(filter_for)]) == list(filter_for):
excl['padding'] = (i, len(value) - i - len(filter_for))
excluded[x] = excl
def isexcluded(lst, i):
# check if the lst is excluded by one of the `excluded` lists
for excl in excluded:
start_padding, end_padding = excl['padding']
# get start and end indexes
start = max(i-start_padding, 0)
end = min(i + len(excl['value']) + end_padding, len(lst))
if list(lst[start:end]) == list(excl['value']):
return True
return False
def get_lists(lists, length, excluded):
for lst in lists:
# get all the 'sublist', parts of the list that are of the same
# length as filter_for
for i in range(len(lst)-length+1):
tests = [list(lst[i:i+length]) == list(filter_for),
not isexcluded(lst, i)]
if all(tests):
yield lst
result = list(get_lists(a, len(filter_for), excluded))
print(result) # python 2: print result
Upvotes: -1
Reputation: 3525
If I understand your requirements correctly, this should return the expected results. Here we convert the lists to strings, and use in
to check for membership.
>>> a = [('1', '2', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '4', '5', 'w', 'w', 'w', 'w'),
('1', '4', '4', '4', 'w', 'w', 'w', 'w')]
>>> filter_for = ''.join(['5', '5', 'w', 'w', 'w', 'w'])
>>> print [tup for tup in a if filter_for in ''.join(tup)]
[('1','2','5','5','w','w','w','w'), ('1','3','5','5','w','w','w','w')]
The below code has been updated to match exact sub-lists in the list of tuples. Instead of pattern matching like in the example above, we take a far different approach here.
We start off by finding the head
and tail
of the filter list. We then find the the indices of where the head
and tail
occur in tup
(we must reverse tup
to find the tail_index
, as index
returns only the first element matched). Using our indices pair, we can then slice that sublist spanning the distance between head
and tail
. If this sublist matches the filter, then we know that only that range exists in the search tuple.
def match_list(filter_list, l):
results = []
filter_for = tuple(filter_list)
head = filter_for[0]
tail = filter_for[-1]
for tup in l:
reverse_tup = tup[::-1]
if head and tail in tup:
try:
head_index = tup.index(head)
index_key = reverse_tup.index(tail)
tail_index = -index_key if index_key else None
if tup[head_index:tail_index] == filter_for:
results.append(tup) # Prints out condition-satisfied tuples.
except ValueError:
continue
return results
Sample output
>>> a = [('1', '2', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '5', '5', 'w', 'w', 'w', 'w'),
('1', '3', '4', '5', 'w', 'w', 'w', 'w'),
('1', '4', '4', '4', 'w', 'w', 'w', 'w'),
('1', '5', '5', '5', 'w', 'w', 'w', 'w')] # <- Does not match!
>>> filter_for = ['5', '5', 'w', 'w', 'w', 'w']
>>> print match_list(filter_for, a)
[('1','2','5','5','w','w','w','w'), ('1','3','5','5','w','w','w','w')]
Upvotes: 2
Reputation: 1052
I'm not sure If I get the point what you're trying. But I would do it as following:
>>>[i for i in a if "".join(filter_for) in "".join(i)]
[('1', '2', '5', '5', 'w', 'w', 'w', 'w'), ('1', '3', '5', '5', 'w', 'w', 'w', 'w')]
Upvotes: 2
Reputation: 9863
Did you mean this
[i for i in a if all([j in i for j in filter_for])]
instead of your line?
[i for i in a if all(j in filter_for for j in a)]
Upvotes: 0