How to find the Intersection of n arrays - coffeescript

I have n arrays or variable length
arr1 = [1,2,3]
arr2 = [1,3,5,8]
....
How can I compute the intersection of those n arrays ?

Consider checking out underscore.js library. It provides function for what you need and a bunch of other usefull functions.
Example from docs:
_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
=> [1, 2]
Simple plain JS implementation can be found here. Same idea in CoffeeScript:
intersect_all = (lists) ->
if lists.length is 0
return []
else return lists[0] if lists.length is 1
partialInt = lists[0]
i = 1
while i < lists.length
partialInt = intersection(partialInt, lists[i])
i++
partialInt

The most efficient way is to use hashsets:
function hashset (elements) {
var i, set = {};
if (!Array.isArray(elements)) return elements;
for (i = 0; i < elements.length; i++) {
set[elements[i]] = true;
}
return set;
};
function intersect (a, b) {
var k
, s1 = hashset(a)
, s2 = hashset(b)
, s3 = {}
for (k in s1) {
if (s2[k]) s3[k] = true;
}
return s3;
};
Object.keys(intersect(arr1,arr2));
// ["1", "3"]
You will find CoffeeScript source of this code, benchmarks for it and some additional information in this question.
If you're going to to intersect huge arrays then I strongly recommend you to use this approach.

Either just use something like _.intersection or study the source of that implementation and rewrite it if you like.

Related

Algolia query by INTERSECTION COUNT with two lists

I need to query some users based on "similar" interests. If a user A has 2 similar interests as user B then it's a match. I want to know if the following query is possible in Algolia.
Lets say I have two objects in some Algolia index with a list property on them (interests):
obj1 = {
interests: ['A', 'B', 'C'],
}
obj2 = {
interests: ['B', 'C', 'D'],
}
And I want to query all objects with interests having at least 2 of the following:
interests: ['A', 'B', 'E']
This should return me just obj1 since is the one having 2 interests alike.
Any ideas?
I'm not sure of an easier way to do this. But let me show my findings
interests: ['A', 'B', 'E']
now to capture your requirement the filters statement should be something like
'(interests:A AND interests:B) OR (interests:A AND interests:E) OR (interests:B AND interests:E)'
which if take as a boolean expression is in the form of AB+AC+BC.
But this particular query cannot be used with algolia according to their docs
For performance reasons, we do not support the following boolean combinations:
...
We limit filter expressions to a conjunction (ANDs) of disjunctions
(ORs). For example you can use filter1 AND (filter2 OR filter3)), but
not ORs of ANDs (e.g. filter1 OR (filter2 AND filter3).
But we can convert the AB+AC+BC to a product of sum format. I used https://www.dcode.fr/boolean-expressions-calculator and obtained the equivalent
(A+B).(A+C).(B+C) which would then be
'(interests:A OR interests:B) AND (interests:A OR interests:E) AND (interests:B OR interests:E)'
The query also depends on how many elements are there in the interests array. For example if interests: ['A', 'E', 'C', 'F'] your final filter query would look in the form
'(interests:A OR interests:E OR interests:C) AND (interests:A OR interests:E OR interests:F) AND (interests:A OR interests:C OR interests:F) AND (interests:E OR interests:C OR interests:F)'
Individual product terms have length of interest array-1 terms
TLDR: '(interests:A OR interests:B) AND (interests:A OR interests:E) AND (interests:B OR interests:E)'
you can use a use a combination generating code and get the filter query.
Here is a JS example based on this solution.
const k_combinations = (set, k) => {
let i, j, combs, head, tailcombs;
if (k > set.length || k <= 0) {
return [];
}
if (k == set.length) {
return [set];
}
if (k == 1) {
combs = [];
for (i = 0; i < set.length; i++) {
combs.push([set[i]]);
}
return combs;
}
combs = [];
for (i = 0; i < set.length - k + 1; i++) {
head = set.slice(i, i+1);
tailcombs = k_combinations(set.slice(i + 1), k - 1);
for (j = 0; j < tailcombs.length; j++) {
combs.push(head.concat(tailcombs[j]));
}
}
return combs;
}
const combinations = (set) => {
let k, i, combs, k_combs;
combs = [];
for (k = 1; k <= set.length; k++) {
k_combs = k_combinations(set, k);
for (i = 0; i < k_combs.length; i++) {
combs.push(k_combs[i]);
}
}
return combs;
}
const generateFilterQuery = (array) => {
const combinationSize = array.length - 1
const combinations = k_combinations(array, combinationSize)
return combinations.map((comb) => `(${comb.map(c => `interests:${c}`).join(" OR ")})`).join(" AND ")
}
console.log(generateFilterQuery(["A","B","E"]))
console.log(generateFilterQuery(["A","B","C","D"]))
console.log(generateFilterQuery(["A","B","C","D","E"]))
After generating the filter query pass it as the value of filters parameter
index.search('',{
filters: generatedQuery
}
).then(({hits}) => console.log(hits))

MATLAB dynamically read/write attributes - getattr, setattr?

class A(): pass
a = A()
setattr(a, 'dog', True)
Is there a MATLAB equivalent? If not, what's the most compact alternative? Currently I do
for i=1:length(keys)
k = keys{i};
v = values{i};
if k == "arg1"
obj.arg1 = v;
elseif k == "arg2"
obj.arg2 = v;
...
Likewise for getattr? If needed, assume all keys are already Properties.
Non-Python readers: setattr(obj, 'a', 1) <=> obj.a = 1 and getattr(obj, 'a') <=> obj.a.
obj.arg1 is the same as obj.('arg1').
So in your code snippet is equivalent to:
for i=1:length(keys)
obj.(keys{i}) = values{i};
end

Iterating over a list in groups of two or more

I like to iterate over a list and split them up in couples like this:
List<String> list = [1,2,3,4,5,6,7,8];
List<Tuple2> listOfTuples = list.take2((value1,value2) => Tuple2(value1,value2));
print(listOfTuples.toString()); // output => [[1,2],[3,4],[5,6],[7,8]]
I know there is a take(count) in dart but I did not find a good example.
I know I can do it with a for loop etc. but I am wondering if there us a more elegant way.
There is nothing built in. The way I'd write this today is:
var list = [1, 2, 3, 4, 5, 6, 7, 8];
var tuples = [
for (int i = 0; i < list.length - 1; i += 2) Tuple2(list[i], list[i + 1]),
];
You could write an extension that gives an api take2 on List that could be used in the way you describe.
extension Take2<T> on List<T> {
List<R> take2<R>(R Function(T, T) transform) => [
for (int i = 0; i < this.length - 1; i += 2)
transform(this[i], this[i + 1]),
];
}

Two variables in for loop using Swift

How to use two variables in for loop?
for j,k in zip(range(x,0,-1),range(y,-1,-1)
I want to implement this in Swift.
If your range is a python function, then the Swift-y solution will be:
let x = 100
let y = 99
let rx = reverse(0...x)
let ry = reverse(-1...y)
for (j,k) in zip(rx, ry) {
println(j, k)
}
if you're looping over a dictionary you can loop like this
for (key,value) in dictionary {
}
if an array etc. you're going to have to use a c style for loop
just sub in whatever start and end indices you need
for var j = 0 , k = 0; j < 10 && k < 10; j++ , k++ {
}
EDIT
missed the zip in there. You can loop like this
for (j,k) in zip(range1, range2) {
}

fastest way to find the union and intersection items among two list

which is the fastest way to find the union and intersection between two lists?
i mean.
i have two list say
List<1>
1
2
3
4
Lis<2>
2
3
Finally i need to get output as
List<3>
Not Defined
2
3
Not Defined
Hope i am clear with my requirement.
Please let me know if i am conusing
LINQ already has Union and Intersection. Your example is neither.
var set = new HashSet(list2)
var list3 = List1.Select(x => set.Contains(x) ? x : null).ToList();
Or you could do the following, which just gives you the intersection:
HashSet<int> list1 = new HashSet<int>() { 1, 2, 3, 4 };
HashSet<int> list2 = new HashSet<int>() { 2, 3 };
List<int> list3 = list1.Intersect(list2).ToList();
for (int i = 0; i < list3.Count; i++)
{
Console.WriteLine(list3[i]);
}
Console.ReadLine();