Reputation: 8315
I have two lists:
string1Elements = ['down', 'down', 'down', 'down']
string2Elements = ['down', 'down', 'right', 'down']
I want to form a list of elements that are common to the two lists, including duplicates. The result I want is as follows:
['down', 'down', 'down']
A way to think about the matching I have in mind is as follows:
0: The status is follows:
string1Elements = ['down', 'down', 'down', 'down']
string2Elements = ['down', 'down', 'right', 'down']
Both lists are the same size, so one is selected arbitrarily. If the lists were not the same size, the shorter one would be selected.
1: Get the first element of string1Elements
(the selected list). Does this element exist in string2Elements
? If it does, append it to the list of matches and remove it from string1Elements
and string2Elements
.
string1Elements = ['down', 'down', 'down']
string2Elements = ['down', 'right', 'down']
matches = ['down']
2: Get the first element of string1Elements
. Does this element exist in string2Elements
? If it does, append it to the list of matches and remove it from string1Elements
and string2Elements
.
string1Elements = ['down', 'down']
string2Elements = ['right', 'down']
matches = ['down', 'down']
3: Get the first element of string1Elements
. Does this element exist in string2Elements
? If it does, append it to the list of matches and remove it from string1Elements
and string2Elements
.
string1Elements = ['down']
string2Elements = ['right']
matches = ['down', 'down', 'down']
4: Get the first element of string1Elements
. Does this element exist in string2Elements
? If it does, append it to the list of matches and remove it from string1Elements
and string2Elements
.
string1Elements = ['down']
string2Elements = ['right']
matches = ['down', 'down', 'down']
5: All elements have been checked.
The above procedure is just to explain how I want to handle duplicate elements. I wouldn't actually want to change the lists string1Elements
and string2Elements
.
I don't think that sets can be used in an obvious way because of the duplicate elements:
matches = list(set(string2Elements).intersection(string1Elements))
I've tried a quick test using list comprehension:
matches = [element for element in string1Elements if element in string2Elements]
Neither of these approaches are sufficient. How could I implement the matching in the way I describe?
Upvotes: 1
Views: 728
Reputation:
You can systematically pop from one list and append to a result list if they match. Because you have popped from the list, it won't match one element in list1 to five elements in list2, as it would've been popped out. An example function:
def intersect(a, b):
if len(b) < len(a): # iff b is shorter than a
a, b = b, a # swap the lists.
b = b[:] # To prevent modifying the lists
return [b.pop(b.index(i)) for i in a if i in b]
Usage:
list1 = ['down', 'down', 'down', 'down']
list2 = ['down', 'down', 'right', 'down']
matches = intersect(list1, list2)
print(" ".join(matches))
# Prints:
down down down
This does exactly as the OP explains how it would be done in the question, except it only removes elements from the shorter list.
One that works on multiple lists could be achieved as follows
def multi_intersect(*args):
if len(args) == 1:
try:
return multi_intersect(*args)
except TypeError:
pass
inters = [item for sublist in args for item in sublist]
for arg in args:
inters = intersect(inters, arg)
return inters
Upvotes: 1