Reputation: 39
so I have a list:
my_list1 = ["p1", "p2", "p4", "p1"]
and I have another list with sublists:
my_list2 = [[1,"p1"], [1,"p2"], [1,"p3"], [1,"p4"], [2, "p1"], [2, "p2"], [2, "p3"], [2, "p4"]]
Now what I want to do is the following:
I want to iterate through my_list1
and then through my_list2
and create a new list that contains the next occurence of each element of my_list1
in my_list2
.
I.e. what I want to obtain is:
new_list = [[1, "p1"], [1, "p2"], [1, "p4"], [2, "p1"]]
I have alrealy tried the following:
new_list = []
for i in my_list1:
for j in my_list2:
if i in j[1]:
new_list.append(j)
Which gives me
new_list = [[1,"p1"], [1,"p2"], [1,"p4"], [2, "p1"], [2, "p2"], [2, "p4"]]
So, again, what I need is that each iteration appends ONLY THE NEXT occurence of an item in my_list2
.
I'm new to Python, so please be gentle. I'm very thankful for any suggestions!
Upvotes: 1
Views: 87
Reputation: 43494
There are a few problems with your code, but the logic is basically correct. You just need to do 2 things differently:
1) Break out of the loop when you append.
2) Remove the item that was appended (so you don't append it again later)
Here is one approach that you can take:
# create a copy of my_list2 because calling pop will mutate the list
temp_list2 = [x for x in my_list2]
new_list = []
for i,x in enumerate(my_list1):
for j,y in enumerate(temp_list2):
if x == y[1]:
new_list.append(temp_list2.pop(j))
break
print(new_list)
#[[1, 'p1'], [1, 'p2'], [1, 'p4'], [2, 'p1']]
Also, don't use in
to compare the values, use ==
instead.
Here is an alternative, more efficient approach using collections.Counter
:
from collections import Counter
list1_counter = Counter(my_list1)
new_list = []
for (value, key) in my_list2:
if key in list1_counter and list1_counter[key] > 0:
new_list.append([value, key])
list1_counter[key] -= 1
print(new_list)
#[[1, 'p1'], [1, 'p2'], [1, 'p4'], [2, 'p1']]
You build a Counter
to count the occurrence of each "key" in my_list1
. Then you iterate over my_list2
and check to see if the key exists in the counter and the count is greater than 0. If so, add the item to the list and decrease the counter.
Upvotes: 3
Reputation: 149736
You could use collections.defaultdict
to group the elements in my_list2
by second item, then consume them while iterating over my_list1
:
>>> from collections import defaultdict, deque
>>> d = defaultdict(deque)
>>> for elem in my_list2:
... d[elem[1]].append(elem)
>>> [d[elem].popleft() for elem in my_list1]
[[1, 'p1'], [1, 'p2'], [1, 'p4'], [2, 'p1']]
Using a deque
instead of a list
allows for efficient pops from the left side.
Upvotes: 2
Reputation: 660
Isnt it a bit straightforward for you , you've stopped it one step early.
my_list1 = ["p1", "p2", "p4", "p1"]
my_list2 = [[1,"p1"], [1,"p2"], [1,"p3"], [1,"p4"], [2, "p1"], [2, "p2"], [2, "p3"], [2, "p4"]]
choice = 0
final_list = []
list_1_length = len(my_list1)
for each_element in my_list2:
if each_element[1] == my_list1[choice]:
final_list.append(each_element)
choice += 1
if choice == list_1_length:
break
Upvotes: 0
Reputation: 378
try this:
new_list = []
tmp_list = my_list2.copy() #only to preserve my_list2
for i in my_list1:
index = 0
for j in tmp_list :
if i in j[1]:
new_list.append(tmp_list.pop(index))
break
index += 1
Upvotes: 1