Reputation: 135
I have two lists of tuples. I want a new list with every member of l2 and every member of l1 that does not begin with the same element from l2.
I used a for loop and my output is ok.
My question is: How can I use the filter function or a list comprehension?
def ov(l1, l2):
l3=l1.copy()
for i in l2:
for j in l1:
if i[0]==j[0]:
l3.pop(l3.index(j))
print (l3+l2)
ov([('c','d'),('c','e'),('a','b'),('a', 'd')], [('a','c'),('b','d')])
The output is:
[('c', 'd'), ('c', 'e'), ('a', 'c'), ('b', 'd')]
Upvotes: 3
Views: 1851
Reputation: 732
Filter is a function which returns a list for all True returns of a function, being used as filter(function(), iterator)
.
def compare(one, two):
for i in two:
if i[0]==one[0]:
print("yes:", one,two)
return False
return True
l1 = [('c','d'),('c','e'),('a','b'),('a', 'd')]
l2 = [('a','c'),('b','d')]
one_liner = lambda n: compare(l1[n], l2) # where n is the tuple in the first list
lets_filter = list(filter(one_liner, range(len(l1))))
final_list = l2.copy()
for i in lets_filter:
final_list.append(l1[i])
print(final_list)
I made this as a way to do it. Lambda might be a bit confusing, alert if you don't understand it, and I'll remake it.
List comprehension is a "ternary operator", if you're familiar with those, in order to make a list in a one-liner.
l1 = [('c','d'),('c','e'),('a','b'),('a', 'd')]
l2 = [('a','c'),('b','d')]
l3 = [l1[n] for n in range(len(l1)) if l1[n][0] not in [l2[i][0] for i in range(len(l2))]]+l2
print(l3)
This code does the trick, but is overwhelming at first. Let me explain what it does.
l1[n] for n in range(len(l1)
goes through all the pairs in l1, in order to see if we can add them. This is done when the if returns True.
l1[n][0] not in
takes the first item, and returns True if doesn't exist in any of the elements of the following list.
[l2[i][0] for i in range(len(l2))]
makes a list from all the first elements of l2.
+l2
is added, as requested.
As a bonus, I'm going to explain how to use else in the same scenario, in case you wanted another result.
l1 = [('c','d'),('a','b'),('c','e'),('a', 'd')]
l2 = [('a','c'),('b','d')]
l3 = [l1[n] if l1[n][0] not in [l2[i][0] for i in range(len(l2))] else ("not", "you") for n in range(len(l1))]+l2
print(l3)
As you can see, I had to switch the order of the operators, but works as it should, adding them in the correct order of l1 (which I changed for the sake of showing).
Upvotes: 0
Reputation: 14216
Here is an approach using filter
:
from operator import itemgetter
f = itemgetter(0)
zval = set(map(itemgetter(0), l2))
list(filter(lambda tup: f(tup) not in zval, l1)) + l2
[('c', 'd'), ('c', 'e'), ('a', 'c'), ('b', 'd')]
Or:
def parser(tup):
return f(tup) not in zval
list(filter(parser, l1)) + l2
[('c', 'd'), ('c', 'e'), ('a', 'c'), ('b', 'd')]
Upvotes: 2
Reputation: 78650
If I understand correctly, this should be the straight forward solution:
>>> l1 = [('c','d'),('c','e'),('a','b'),('a', 'd')]
>>> l2 = [('a','c'),('b','d')]
>>>
>>> starters = set(x for x, _ in l2)
>>> [(x, y) for x, y in l1 if x not in starters] + l2
[('c', 'd'), ('c', 'e'), ('a', 'c'), ('b', 'd')]
This can be generalized to work with longer tuples with extended iterable unpacking.
>>> starters = set(head for head, *_ in l2)
>>> [(head, *tail) for head, *tail in l1 if head not in starters] + l2
[('c', 'd'), ('c', 'e'), ('a', 'c'), ('b', 'd')]
Upvotes: 5