Intersection of two lists including duplicates?
You can use collections.Counter
for this, which will provide the lowest count found in either list for each element when you take the intersection.
from collections import Counter
c = list((Counter(a) & Counter(b)).elements())
Outputs:
[1, 1, 2, 3, 4]
Common elements in two lists preserving 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]
Intersection of two lists, keeping duplicates in the first list
What do you mean you don't want to use loops? You're going to have to iterate over it one way or another. Just take in each item individually and check if it's in array2
as you go:
items = set(array2)
found = [i for i in array1 if i in items]
Furthermore, depending on how you are going to use the result, consider having a generator:
found = (i for i in array1 if i in array2)
so that you won't have to have the whole thing in memory all at once.
Python: intersection of 2 lists keeping duplicates from both lists
Here is the answer to your question as asked:
import collections
for A,B,expected_output in (
([1,1,2,3], [1,1,2,4], [1,1,1,1,2]),
([1,1,2,3], [1,2,4], [1,1,2])):
cntA = collections.Counter(A)
cntB = collections.Counter(B)
output = [
x for x in sorted(set(A) & set(B)) for i in range(cntA[x]*cntB[x])]
assert output == expected_output
Here is the answer to the question as originally interpreted by myself and two others:
import collections
A=[1,1,2,3]
B=[1,1,2,4]
expected_output = [1,1,1,1,2,2]
cntA = collections.Counter(A)
cntB = collections.Counter(B)
cnt_sum = collections.Counter(A) + collections.Counter(B)
output = [x for x in sorted(set(A) & set(B)) for i in range(cnt_sum[x])]
assert output == expected_output
You can find the collections.Counter()
documentation here. collections
is a great module and I highly recommend giving the documentation on the whole module a read.
I realized you don't actually need to find the intersection of the sets, because the "count of a missing element is zero" according to the documentation:
import collections
for A,B,expected_output in (
([1,1,2,3], [1,1,2,4], [1,1,1,1,2]),
([1,1,2,3], [1,2,4], [1,1,2])):
cntA = collections.Counter(A)
cntB = collections.Counter(B)
output = [
x for x in sorted(set(A)) for i in range(cntA[x]*cntB[x])]
assert output == expected_output
Intersection of two lists maintaining duplicate values in Kotlin
This:
val a = listOf(1, 2, 3, 3, 4, 5, 5, 5, 6)
val b = listOf(1, 3, 3, 3, 4, 4, 5, 6, 6, 7)
var counter = 0
a.intersect(b).forEach { x -> counter += listOf(a.count {it == x}, b.count {it == x}).min()!! }
println(counter)
will print
6
It uses the intersection of the 2 lists and by iterating through each of its items, adds to the counter the minimum number of occurrences of the item in both lists.
With this import:
import kotlin.math.min
you can avoid the creation of a list at each iteration and simplify to:
a.intersect(b).forEach { x-> counter += min(a.count {it == x}, b.count {it == x}) }
Courtesy of Arjan, a more elegant way to calculate the sum:
val result = a.intersect(b).map { x -> min(a.count {it == x}, b.count {it == x}) }.sum()
How to find list intersection?
If order is not important and you don't need to worry about duplicates then you can use set intersection:
>>> a = [1,2,3,4,5]
>>> b = [1,3,5,6]
>>> list(set(a) & set(b))
[1, 3, 5]
Intersection of two lists with duplicate elements
A possible solution to obtain the intersection D
of [X|A]
and B
is:
- Suppose, as induction hypothesis, that the intersection of
A
andB
isC
(without repetition). - Therefore:
- if
X
is member ofC
orX
is not member ofB
, thenD
is equal toC
; - otherwise,
D
is equal to[X|C]
.
- if
% inter(++Set1, ++Set2, -Set3)
inter([], _, []).
inter([X|A], B, D) :-
inter(A, B, C),
( ( memberchk(X, C)
; \+ memberchk(X, B) )
-> D = C
; D = [X|C] ).
Example:
?- inter([a,b,b,a], [c,b,b,c,e,f], S).
S = [b].
Intersection of two lists with repetitions
Map one of the sequences to a dictionary of items to the count of times they appear, then for each item in the other sequence, if it's in the collection, and the value of the lookup is greater than zero, yield it and decriment:
public static IEnumerable<T> IntersectWithRepetitons<T>(this IEnumerable<T> first,
IEnumerable<T> second)
{
var lookup = second.GroupBy(x => x)
.ToDictionary(group => group.Key, group => group.Count());
foreach (var item in first)
if (lookup.ContainsKey(item) && lookup[item] > 0)
{
yield return item;
lookup[item]--;
}
}
This ensures that items are yields for each time they are duplicated in both sets.
You could use TryGetValue
to remove a few dictionary lookups, but it sacrifices a lot of the method's elegance, so I just didn't have it in me to do that. If you care about performance, it's not a bad thing to change.
Related Topics
How to Make Built-In Containers (Sets, Dicts, Lists) Thread Safe
Equivalent of Numpy.Argsort() in Basic Python
How to Change Sprite Colours in Pygame
How to Perform Two-Dimensional Interpolation Using Scipy
Passing Csrftoken with Python Requests
How to Create an Incrementing Filename in Python
Why Doesn't Print Work in a Lambda
Matplotlib Yaxis Range Display Using Absolute Values Rather Than Offset Values
How to Sort a List by Length of String Followed by Alphabetical Order
Differencebetween an Opencv Bgr Image and Its Reverse Version Rgb Image[:,:,::-1]
How to Tell Distutils to Use Gcc
How to Remove the Space Between Subplots in Matplotlib.Pyplot
Calculating Pearson Correlation and Significance in Python
Making an Executable in Cython