This question already has answers here:
Intersection of two lists including duplicates?
(6 answers)
Closed 1 year ago.
The goal is to find common elements in two lists while preserving duplicates.
For example,
Input:
a = [1,3,3,4,5,5]
b = [3,5,5,5,6]
Expected output:
[3,5,5]
I tried set.intersection but set operatons would eliminate duplicates.
Here is my suggestion:
from collections import Counter
ac=Counter(a)
bc=Counter(b)
res=[]
for i in set(a).intersection(set(b)):
res.extend([i] * min(bc[i], ac[i]))
>>> print(res)
[3, 5, 5]
You can use a Counter of your lists and use those keys that occure in both and the minimal amount of their values:
from collections import Counter
a = [1,3,3,4,5,5]
b = [3,5,5,5,6]
ca = Counter(a)
cb = Counter(b)
result = [a for b in ([key] * min(ca[key], cb[key])
for key in ca
if key in cb) for a in b]
print(result)
Output:
[3,5,5]
a = [1,3,3,4,5,5]
b = [3,5,5,5,6]
def findout(a, b):
a = a.copy()
output = []
for i in b:
if i in a:
a.remove(i)
output.append(i)
return output
result = findout(a, b)
print(result) # [3, 5, 5]
may work.
Using Counter from collections module.
from collections import Counter
a = [1,3,3,4,5,5]
b = [3,5,5,5,6]
ans = []
a_count = Counter(a)
b_count = Counter(b)
for i in a_count:
if i in b_count:
ans.extend([i]*min(a_count[i], b_count[i]))
print(ans)
Output
[3, 5, 5]
The answer depends if the lists are always sorted like in your example. If so, you can do a cursor approach where
index_a = 0
index_b = 0
common_elements = []
while index_a < len(a) and index_b < len(b):
if a[index_a] < b[index_b]:
# then a should check the next number, b should stay
index_a += 1
elif a[index_a] > b[index_b]:
# then the reverse
index_b += 1
else:
# they are equal
common_elements.append(a[index_a])
index_a += 1
index_b += 1
However, if they are not sorted like that you're better off maybe doing the set intersection and then turning it back into a list and then for each element add duplicates to equal min(a.count(el), b.count(el))?
That preserving duplicates got my head but finally got a solution
a = [1,3,3,4,5,5]
b = [3,5,5,5,6]
c=[]
def dublicate_finder(a,b):
global c
if len(a)>len(b):
for i in range(len(b)):
if b[i] in a:
c.append(b[i])
remove_index=a.index(b[i],0,len(a))
del a[remove_index]
if len(a)>len(b):
for i in range(len(a)):
if a[i] in b:
c.append(a[i])
remove_index=b.index(a[i],0,len(b))
del a[remove_index]
return c
Try this. You can use the any operator to check if the element is equal to that in other list.
Then remove the element
a = [1,3,3,4,5,5]
b = [3,5,5,5,6]
l3=[]
for i in b:
if any(i==j for j in a):
l3.append(i)
a.remove(i)
print(l3)
Although set.intersection removes duplicates, it can be very useful nonetheless:
a_set = set(a)
b_set = set(b)
intr = a_set.intersection(set_b)
result = [element for element in a if element in intr]
That should work
Related
Edit: Removed undefined variable.
So my code is basically, trying to compare if a value of one list is present in another. If so append the value to 3rd list. If the value is not present, then append to 4th list. What is the most efficient and readable way to do this task. Example of my code:
a = [1,2,3]
b = [2,3,4,5,6,7]
c = []
d = []
for ele in a:
if ele in b:
c.append(ele )
else:
d.append(ele)
a=[2,3,4,5]
b=[3,5,7,9]
c = [value for value in a if value in b]
d = [value for value in a if value not in b]
print(f'Present in B: {c}')
print(f"Not present in B: {d}")
c = [i for i in a if i in b]
d = [i for i in a if i not in b]
The best way to solve this is by using sets.
import random
a = [random.randint(1, 15) for _ in range(5)]
b = [random.randint(1, 15) for _ in range(7)]
print(a)
print(b)
set_a = set(a)
set_b = set(b)
set_intersection = set_a.intersection(set_b)
set_diff = set_a.difference(set_b)
print(list(set_intersection))
print(list(set_diff))
I'm trying to write a code which returns ALL indices of the elements from a list, which are repeated EXACTLY TWICE. I'm having trouble with my own algorithm. My code only returns the FIRST occurrence it finds. I want this fixed. Here's my own code (it's somehow weird, I know):
from collections import Counter
length = int(input())
user_input = [int(x) for x in input().split()]
occurrances = Counter(user_input)
check_list = []
check_list.append(list(occurrances.keys())[list(occurrances.values()).index(2)])
print(check_list)
I appreciate any help from anyone. Thanks in advance.
Try this:
from collections import Counter
userInput = input().split()
counter = Counter(userInput)
print([x[0] for x in counter.items() if x[1] == 2])
To find the indices of the items occurring twice.
>>> L = [1,2,3,1,4,6,6]
>>> from collections import Counter
>>> c = Counter(L)
>>> for key in filter(lambda x: c[x] == 2, c):
one = L.index(key)
two = L.index(key, one+1)
print(key, 'found at indexes', ' '.join(map(str, [one, two])))
1 found at indexes 0 3
6 found at indexes 5 6
To get the indexes you can use Counter and enumerate inside a list comprehension:
from collections import Counter
L = [1,2,3,4,3,4,2,3,5]
L2 = [i for c in [Counter(L)] for i,v in enumerate(L) if c[v]==2]
print(L2)
[1, 3, 5, 6]
If you're not allowed to use libraries, you can do it without Counter (although it will run slower):
L2 = [i for i,v in enumerate(L) if L.count(v)==2]
This should work if you are looking for the indexes
from collections import Counter
user_input = [int(x) for x in input().split()]
occurrences = Counter(user_input)
keys = [key for key in occurrences.keys() if occurrences[key]==2 ]
check_list = [x for x in range(len(user_input)) if user_input[x] in keys]
print(check_list)
I have N lists, and would like to know which elements are present in strictly X of those lists. I understand that if I have two lists, it's rather straightforward:
lst_a = [1,2,3]
lst_b = [1,2,5]
overlap = list(set(a) & set(b))
What if I have, say, 5 lists, and want to know which elements are in strictly 4 of those?
Merge using counters:
from collections import Counter
lst_a = [1,2,3]
lst_b = [1,2,5]
lsts = [lst_a, lst_b]
counter = Counter()
for lst in lsts:
unique = set(lst)
counter += Counter(unique)
n = 2
print(f"elements in exactly {n} lsts:")
for k, v in counter.items():
if v == n:
print(k)
Similar to #wim's code, but in a more concise manner:
[i for i, c in sum(map(Counter, lsts), Counter()).items() if c == 2]
If the items in the input lists are not unnecessarily unique you can map the lists to sets first:
[i for i, c in sum(map(Counter, map(set, lsts)), Counter()).items() if c == 2]
This returns:
[1, 2]
I am trying to generate a list that combines elements of two other lists, one is a value and one is not.
I've tried having two separate lists with and using the join function and append function to combine the two elements together at the certain stage.
To match the length of list d to list a I've used a while loop as a counter.
a=7*[1]
b=[1,2,3,4,5]
c=['a','b','c']
d=[]
The outcome i'm trying to achieve is such that:
list d becomes the length of list a
& is a combination of list b and list c
d=[1a,1b,1c,2a,2b,2c,3a]
Can think of a Naive solution for now
def create(bk, ck, len_required):
dk = []
for bitem in bk:
for citem in ck:
dk.append(str(bitem) + citem)
if len(dk) == len_required:
return dk
len_required = len(a)
b = [1, 2, 3, 4, 5]
c = ['a', 'b', 'c']
d = create(b, c, len_required)
result = [str(b[int(i / len(c)) % len(b)]) + str(c[i % len(c)]) for i in range(len(a))]
This iterates i from 0 to len(a) and concatenates b[int(i / len(c)) % len(b)] and c[i % len(c)] in the output.
You could do it with a list comprehension:
d = [str(v)+L for v in b*len(a) for L in c][:len(a)]
or, if you're allowed to use itertools:
from itertools import cycle
cycleA = cycle(str(v)+L for v in b for L in c)
d = [ next(cycleA) for _ in a ]
I'm trying to create a function that takes in 2 lists and returns the list that only has the differences of the two lists.
Example:
a = [1,2,5,7,9]
b = [1,2,4,8,9]
The result should print [4,5,7,8]
The function so far:
def xor(list1, list2):
list3=list1+list2
for i in range(0, len(list3)):
x=list3[i]
y=i
while y>0 and x<list3[y-1]:
list3[y]=list3[y-1]
y=y-1
list3[y]=x
last=list3[-1]
for i in range(len(list3) -2, -1, -1):
if last==list3[i]:
del list3[i]
else:
last=list3[i]
return list3
print xor([1,2,5,7,8],[1,2,4,8,9])
The first for loop sorts it, second one removes the duplicates. Problem is the result is
[1,2,4,5,7,8,9] not [4,5,7,8], so it doesn't completely remove the duplicates? What can I add to do this.
I can't use any special modules, .sort, set or anything, just loops basically.
You basically want to add an element to your new list if it is present in one and not present in another. Here is a compact loop which can do it. For each element in the two lists (concatenate them with list1+list2), we add element if it is not present in one of them:
[a for a in list1+list2 if (a not in list1) or (a not in list2)]
You can easily transform it into a more unPythonic code with explicit looping through elements as you have now, but honestly I don't see a point (not that it matters):
def xor(list1, list2):
outputlist = []
list3 = list1 + list2
for i in range(0, len(list3)):
if ((list3[i] not in list1) or (list3[i] not in list2)) and (list3[i] not in outputlist):
outputlist[len(outputlist):] = [list3[i]]
return outputlist
Use set is better
>>> a = [1,2,5,7,9]
>>> b = [1,2,4,8,9]
>>> set(a).symmetric_difference(b)
{4, 5, 7, 8}
Thanks to #DSM, a better sentence is:
>>> set(a)^set(b)
These two statements are the same. But the latter is clearer.
Update: sorry, I did not see the last requirement: cannot use set. As far as I see, the solution provided by #sashkello is the best.
Note: This is really unpythonic and should only be used as a homework answer :)
After you have sorted both lists, you can find duplicates by doing the following:
1) Place iterators at the start of A and B
2) If Aitr is greater than Bitr, advance Bitr after placing Bitr's value in the return list
3) Else if Bitr is greater than Aitr, advance Aiter after placing Aitr's value in the return list
4) Else you have found a duplicate, advance Aitr and Bitr
This code works assuming you've got sorted lists. It works in linear time, rather than quadratic like many of the other solutions given.
def diff(sl0, sl1):
i0, i1 = 0, 0
while i0 < len(sl0) and i1 < len(sl1):
if sl0[i0] == sl1[i1]:
i0 += 1
i1 += 1
elif sl0[i0] < sl1[i1]:
yield sl0[i0]
i0 += 1
else:
yield sl1[i1]
i1 += 1
for i in xrange(i0, len(sl0)):
yield sl0[i]
for i in xrange(i1, len(sl1)):
yield sl1[i]
print list(diff([1,2,5,7,9], [1,2,4,8,9]))
Try this,
a = [1,2,5,7,9]
b = [1,2,4,8,9]
print set(a).symmetric_difference(set(b))
Simple, but not particularly efficient :)
>>> a = [1,2,5,7,9]
>>> b = [1,2,4,8,9]
>>> [i for i in a+b if (a+b).count(i)==1]
[5, 7, 4, 8]
Or with "just loops"
>>> res = []
>>> for i in a+b:
... c = 0
... for j in a+b:
... if i==j:
... c += 1
... if c == 1:
... res.append(i)
...
>>> res
[5, 7, 4, 8]