find intersection elements in arrays in an array - javascript

I need to construct a function intersection that compares input arrays and returns a new array with elements found in all of the inputs.
The following solution works if in each array the numbers only repeat once, otherwise it breaks. Also, I don't know how to simplify and not use messy for loops:
function intersection(arrayOfArrays) {
let joinedArray = [];
let reducedArray = [];
for (let iOuter in arrayOfArrays) {
for (let iInner in arrayOfArrays[iOuter]) {
joinedArray.push(arrayOfArrays[iOuter][iInner]);
}
return joinedArray;
}
for (let i in joinedArray.sort()) {
if (joinedArray[i] === joinedArray[ i - (arrayOfArrays.length - 1)]) {
reducedArray.push(joinedArray[i]);
}
}
return reducedArray;
}

Try thhis:-
function a1(ar,ar1){
x = new Set(ar)
y = new Set(ar1)
var result = []
for (let i of x){
if (y.has(i)){
result.push(i)
}
}
if (result){return result}
else{ return 0}
}
var a= [3,4,5,6]
var b = [8,5,6,1]
console.log(a1(a,b)) //output=> [5,6]

Hopefully this snippet will be useful
var a = [2, 3, 9];
var b = [2, 8, 9, 4, 1];
var c = [3, 4, 5, 1, 2, 1, 9];
var d = [1, 2]
function intersect() {
// create an empty array to store any input array,All the comparasion
// will be done against this one
var initialArray = [];
// Convert all the arguments object to array
// there can be n number of supplied input array
// sorting the array by it's length. the shortest array
//will have at least all the elements
var x = Array.prototype.slice.call(arguments).sort(function(a, b) {
return a.length - b.length
});
initialArray = x[0];
// loop over remaining array
for (var i = 1; i < x.length; i++) {
var tempArray = x[i];
// now check if every element of the initial array is present
// in rest of the arrays
initialArray.forEach(function(item, index) {
// if there is some element which is present in intial arrat but not in current array
// remove that eleemnt.
//because intersection requires element to present in all arrays
if (x[i].indexOf(item) === -1) {
initialArray.splice(index, 1)
}
})
}
return initialArray;
}
console.log(intersect(a, b, c, d))

There is a nice way of doing it using reduce to intersect through your array of arrays and then filter to make remaining values unique.
function intersection(arrayOfArrays) {
return arrayOfArrays
.reduce((acc,array,index) => { // Intersect arrays
if (index === 0)
return array;
return array.filter((value) => acc.includes(value));
}, [])
.filter((value, index, self) => self.indexOf(value) === index) // Make values unique
;
}

You can iterate through each array and count the frequency of occurrence of the number in an object where the key is the number in the array and its property being the array of occurrence in an array. Using the generated object find out the lowest frequency of each number and check if its value is more than zero and add that number to the result.
function intersection(arrayOfArrays) {
const frequency = arrayOfArrays.reduce((r, a, i) => {
a.forEach(v => {
if(!(v in r))
r[v] = Array.from({length:arrayOfArrays.length}).fill(0);
r[v][i] = r[v][i] + 1;
});
return r;
}, {});
return Object.keys(frequency).reduce((r,k) => {
const minCount = Math.min(...frequency[k]);
if(minCount) {
r = r.concat(Array.from({length: minCount}).fill(+k));
}
return r;
}, []);
}
console.log(intersection([[2,3, 45, 45, 5],[4,5,45, 45, 45, 6,7], [3, 7, 5,45, 45, 45, 45,7]]))

Related

How do I sum the elements of an arbitrary number of arrays with different lengths in Javascript?

While the code below will satisfy adding two arrays with different lengths, how can I modify this to accept an arbitrary number of arrays as arguments so that, for example, ([1, 2, 3], [4, 5], [6]) will return an array of [11, 7, 3] ?
const addTogether = (arr1, arr2) => {
let result = [];
for (let i = 0; i < Math.max(arr1.length, arr2.length); i++) {
result.push((arr1[i] || 0) + (arr2[i] || 0))
}
return result
}
Use a nested array, and loop over the array rather than hard-coding two array variables.
You can use arrays.map() to get all the lengths so you can calculate the maximum length. And arrays.reduce() to sum up an element in each array.
const addTogether = (...arrays) => {
let result = [];
let len = Math.max(...arrays.map(a => a.length));
for (let i = 0; i < len; i++) {
result.push(arrays.reduce((sum, arr) => sum + (arr[i] || 0), 0));
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]));
You can use arguments object inside function.
arguments is an Array-like object accessible inside functions that contains the values of the arguments passed to that function.
const addTogether = function () {
const inputs = [...arguments];
const maxLen = Math.max(...inputs.map((item) => item.length));
const result = [];
for (let i = 0; i < maxLen; i ++) {
result.push(inputs.reduce((acc, cur) => acc + (cur[i] || 0), 0));
}
return result;
};
console.log(addTogether([1,2,3], [4,5], [6]));
Solution:
const addTogether = (...args) => {
let result = [];
let max = 0;
args.forEach((arg)=>{
max = Math.max(max,arg.length)
})
for(let j=0;j<max;j++){
result[j]= 0
for (let i = 0; i < args.length; i++) {
if(args[i][j])
result[j]+= args[i][j]
}
}
return result
}
console.log(addTogether([1, 2, 3], [4, 5], [6]))
Output:[ 11, 7, 3 ]
Use rest param syntax to accept an arbitrary number of arguments. Sort the outer array by their length in descending order. By using destructuring assignment separate the first and rest of the inner arrays. At last use Array.prototype.map() to traverse the first array as it is the largest array and use Array.prototype.reduce() method to get the summation.
const addTogether = (...ar) => {
ar.sort((x, y) => y.length - x.length);
const [first, ...br] = ar;
return first.map(
(x, i) => x + br.reduce((p, c) => (i < c.length ? c[i] + p : p), 0)
);
};
console.log(addTogether([1, 2, 3], [4, 5], [6]));
Instead of using a for loop that requires you to know the lengths of each array, try using something that doesn't. For example - while loop.
Increment using a dummy variable and reset it for each array and set condition for loop termination as - arr[i] === null.

Find indices of all duplicate records in js

Suppose I have an array as below:
Arr1 = [12,30,30,60,11,12,30]
I need to find index of elements which are repeated in array e.g.
ans: 0,1,2,5,6
I've tried this code but it is considering just single element to check duplicates.
First get all the duplicates using filter() and then using reduce() get he indexes of only those elements of array which are in dups
const arr = [12,30,30,60,11,12,30];
const dups = arr.filter(x => arr.indexOf(x) !== arr.lastIndexOf(x));
const res = arr.reduce((ac, a, i) => {
if(dups.includes(a)){
ac.push(i)
}
return ac;
}, []);
console.log(res)
The time complexity of above algorithm is O(n^2). If you want O(n) you can use below way
const arr = [12,30,30,60,11,12,30];
const dups = arr.reduce((ac, a) => (ac[a] = (ac[a] || 0) + 1, ac), {})
const res = arr.reduce((ac, a, i) => {
if(dups[a] !== 1){
ac.push(i)
}
return ac;
}, []);
console.log(res)
You could use simple indexOf and the loop to get the duplicate indexes.
let arr = [12,30,30,60,11,12,30]
let duplicate = new Set();
for(let i = 0; i < arr.length; i++){
let index = arr.indexOf(arr[i], i + 1);
if(index != -1) {
duplicate.add(i);
duplicate.add(index);
}
}
console.log(Array.from(duplicate).sort().toString());
A slightly different approach with an object as closure for seen items which holds an array of index and the first array, in which later comes the index and a necessary flattening of the values.
This answer is based on the question how is it possible to insert a value into an already mapped value.
This is only possible by using an object reference which is saved at the moment where a value appears and which is not seen before.
Example of unfinished result
[
[0],
[1],
2,
[],
[],
5,
6
]
The final Array#flat removes the covering array and shows only the index, or nothing, if the array remains empty.
[0, 1, 2, 5, 6]
var array = [12, 30, 30, 60, 11, 12, 30],
indices = array
.map((o => (v, i) => {
if (o[v]) { // if is duplicate
o[v][1][0] = o[v][0]; // take the first index as well
return i; // return index
}
o[v] = [i, []]; // save index
return o[v][1]; // return empty array
})({}))
.flat() // remove [] and move values out of array
console.log(indices);
You could use Array#reduce method
loop the array with reduce.At the time find the index of argument
And check the arguments exist more than one in the array using Array#filter
Finaly push the index value to new accumulator array.If the index value already exist in accumalator.Then pass the currentIndex curInd of the array to accumulator
const arr = [12, 30, 30, 60, 11, 12, 30];
let res = arr.reduce((acc, b, curInd) => {
let ind = arr.indexOf(b);
if (arr.filter(k => k == b).length > 1) {
if (acc.indexOf(ind) > -1) {
acc.push(curInd)
} else {
acc.push(ind);
}
}
return acc;
}, []);
console.log(res)
Below code will be easiest way to find indexes of duplicate elements
var dupIndex = [];
$.each(Arr1, function(index, value){
if(Arr1.filter(a => a == value).length > 1){ dupIndex.push(index); }
});
This should work for you

Return numbers which appear only once (JavaScript)

Say I have the array [1,2,3,5,2,1,4]. How do I get make JS return [3,4,5]?
I've looked at other questions here but they're all about delete the copies of a number which appears more than once, not both the original and the copies.
Thanks!
Use Array#filter method twice.
var data = [1, 2, 3, 5, 2, 1, 4];
// iterate over elements and filter
var res = data.filter(function(v) {
// get the count of the current element in array
// and filter based on the count
return data.filter(function(v1) {
// compare with current element
return v1 == v;
// check length
}).length == 1;
});
console.log(res);
Or another way using Array#indexOf and Array#lastIndexOf methods.
var data = [1, 2, 3, 5, 2, 1, 4];
// iterate over the array element and filter out
var res = data.filter(function(v) {
// filter out only elements where both last
// index and first index are the same.
return data.indexOf(v) == data.lastIndexOf(v);
});
console.log(res);
You can also use .slice().sort()
var x = [1,2,3,5,2,1,4];
var y = x.slice().sort(); // the value of Y is sorted value X
var newArr = []; // define new Array
for(var i = 0; i<y.length; i++){ // Loop through array y
if(y[i] != y[i+1]){ //check if value is single
newArr.push(y[i]); // then push it to new Array
}else{
i++; // else skip to next value which is same as y[i]
}
}
console.log(newArr);
If you check newArr it has value of:
[3, 4, 5]
var arr = [1,2,3,5,2,1,4]
var sorted_arr = arr.slice().sort(); // You can define the comparing function here.
var nonduplicates = [];
var duplicates=[];
for (var i = 0; i < arr.length; i++) {
if (sorted_arr[i + 1] == sorted_arr[i]) {
duplicates.push(sorted_arr[i]);
}else{
if(!duplicates.includes(sorted_arr[i])){
nonduplicates.push(sorted_arr[i]);
}
}
}
alert("Non duplicate elements >>"+ nonduplicates);
alert("Duplicate elements >>"+duplicates);
I think there could exists option with Map.
function unique(array) {
// code goes here
const myMap = new Map();
for (const el of array) {
// save elements of array that came only once in the same order
!myMap.has(el) ? myMap.set(el, 1) : myMap.delete(el);
}
return [...myMap.keys()];
}
const array = [1,2,3,5,2,1,4];
//[11, 23, 321, 300, 50, 23, 100,89,300];
console.log(unique(array));

JavaScript - Special case of subset sum algorithm

From a given array of positive integers, I want to know if the sum of E elements from the array is equal to a given number N.
For example, given the array arr = [1, 2, 3, 4] , e = 3 and n = 9. It means if the sum of 3 elements in arr equals to 9. The result is true since 2 + 3 + 4 is equal to 9.
Another example with arr = [1, 2, 3, 4] , e = 2 and n = 7. It is true since 3 + 4 is equal to 7.
I'm trying to resolve it with recursion, but I'm stuck. My idea is to nest loops dynamically to walk through the elements to the array and compare them.
My attempt is this:
function subsetsum(arr, elements, n) {
loop(arr, elements, n, [], 0);
}
function loop(arr, elements, n, aux, index) {
if(aux.length != elements) {
aux[index] = arr.length - 1;
loop(arr, elements, n, aux, index + 1);
} else {
if ((elements - index + 1) < 0) {
return 0;
} else {
if (aux[elements - index + 1] > 0) {
aux[elements - index + 1]--;
loop(arr, elements, n, aux, index);
}
}
}
}
subsetsum([1, 2, 3, 4], 3, 9));
A related question is at Find the highest subset of an integer array whose sums add up to a given target. That can be modified to restrict the number of elements in the subset as follows:
// Find subset of a, of length e, that sums to n
function subset_sum(a, e, n) {
if (n < 0) return null; // Nothing adds up to a negative number
if (e === 0) return n === 0 ? [] : null; // Empty list is the solution for a target of 0
a = a.slice();
while (a.length) { // Try remaining values
var v = a.shift(); // Take next value
var s = subset_sum(a, e - 1, n - v); // Find solution recursively
if (s) return s.concat(v); // If solution, return
}
}
I've been playing around with this for a while and decided to use a short-cut, mainly the permutation code from this previous SO question.
My code uses basically uses the permutation code to create an array of all the possible permutations from the input array, then for each array (using map) grabs a slice corresponding to the number specified as amount, sums that slice and if it is the same as total returns true.
some then returns the final result as to whether there are any permutations that equals the total.
function checker(arr, amount, total) {
var add = function (a, b) { return a + b; }
return permutator(arr).map(function(arr) {
var ns = arr.slice(0, amount);
var sum = ns.reduce(add);
return sum === total;
}).some(Boolean);
}
checker([1, 2, 3, 4], 3, 9); // true
I've included two demos - 1) a demo showing this code, and 2) code that provides a more detailed breakdown: basically map returns an object containing the slice info, the sum totals and whether the condition has been met.
This is probably not what you're looking for because it's a bit long-winded, but it was certainly useful for me to investigate :)
Edit - alternatively here's a hacked version of that permutation code from the previous question that delivers the results and an array of matches:
function permutator(inputArr, amount, total) {
var results = [], out = [];
function permute(arr, memo) {
var cur, memo = memo || [];
var add = function (a, b) { return a + b; }
for (var i = 0; i < arr.length; i++) {
cur = arr.splice(i, 1);
if (arr.length === 0) {
results.push(memo.concat(cur));
}
var a = arr.slice();
// this is the change
var sum = memo.concat(cur).reduce(add);
if (memo.concat(cur).length === amount && sum === total) {
out.push(memo.concat(cur))
}
permute(a, memo.concat(cur));
arr.splice(i, 0, cur[0]);
}
return [results, out];
}
return permute(inputArr);
}
permutator([1,2,3,4], 3, 9);
DEMO
If I understand you correctly, the solution of this task must be simple like this:
function subsetsum(arr, countElements, sum) {
var length = arr.length-1;
var temp = 0;
var lastElement = length-countElements;
console.log(lastElement);
for (var i = length; i > lastElement; i--) {
temp = temp+arr[i];
console.log('Sum: '+temp);
}
if (temp === sum) {
console.log('True!');
} else {console.log('False!')}
};
subsetsum([1, 2, 3, 4], 2, 7);

Find Max value of each x value in JavaScript multidimensional array

I want to 'reduce' the array to only max values for each x (or index 0) value in a JavaScript multidimensional array.
My Array is as follows:
var mulitple = [["1/2013", 1],
["1/2013", 5],
["1/2013", 7],
["1/2013", 6],
["1/2013", 5],
["2/2013", 7],
["2/2013", 10],
["2/2013", 10],
["3/2013", 7],
["3/2013", 10],
["3/2013", 10],
["4/2013", 1],
["4/2013", 5],
["4/2013", 7],
["4/2013", 6],
["4/2013", 5],
["5/2013", 7]];
So the final result should be as follows:
[["1/2013", 7],
["2/2013", 10],
["3/2013", 10],
["4/2013", 7],
["5/2013", 7]];
How can I achieve this in JavaScript.
EDIT:
Aww man who voted my question down.
Anyhow, this is what I have come up with.
var max = 0;
var newarray = [];
for (var i = 1; i < mulitple.length; i++) {
if (mulitple[i - 1][0] == mulitple[i][0]) {
if (mulitple[i - 1][1] > max) {
max = mulitple[i - 1][1];
}
}
else {
if (mulitple[i - 1][1] > max) {
max = mulitple[i - 1][1];
}
newarray.push([mulitple[i - 1][0], max]);
max = 0;
}
}
newarray.push([mulitple[mulitple.length - 1][0], max]);
The problem that I am having is that I can't get that last value (for the lone record) to get in the array. This was my result after I ran the code above.
[["1/2013", 7], ["2/2013", 10], ["3/2013", 10], ["4/2013", 7], ["5/2013", 0]]
This assumes that original array is already sorted. If not, you will have to write additional function to sort out.
function findMaximums(data) {
var out = [], maximums = {}, order = new Set;
data.reduce(function(acc, pair) {
if (
// Accumulator has value and it's lower than current
(acc[pair[0]] && acc[pair[0]][1] < pair[1]) ||
// Accumulator doesn't have value
!acc[pair[0]]
) {
acc[pair[0]] = pair; // Store maximum in accumulator
order.add(pair[0]) // Store order in set
}
return acc;
}, maximums);
order.forEach(function(key) {
out.push(maximums[key]); // Populate out with maximums by order
});
return out;
}
findMaximums(multiple);
/*[
[
"1/2013",
7
],
[
"2/2013",
10
],
[
"3/2013",
10
],
[
"4/2013",
7
],
[
"5/2013",
7
]
]*/
Update 1: same, but without Set.
function findMaximums(data) {
var order = [];
var maximums = data.reduce(function(acc, pair) {
if (
// Accumulator has value and it's lower than current
(acc[pair[0]] && acc[pair[0]][2] < pair[1]) ||
// Accumulator doesn't have value
!acc[pair[0]]
) {
// Store maximum
acc[pair[0]] = pair;
// Store order
if (order.indexOf(pair[0]) === -1) {
order.push(pair[0])
}
}
return acc;
}, {});
return order.map(function(key) {
return maximums[key]; // Populate out with maximums by order
});
}
Update 2: Shorter version.
function findMaximums(data) {
return data.filter(function(p1, i1) {
return !data.some(function(p2, i2) {
return p1[0] === p2[0] && ( (p1[1] < p2[1]) || (p1[1] === p2[1] && i1 > i2) );
});
});
}
In this version I let pair to remain in output if there are no other pairs in input data that:
Have same month.
Have bigger value.
or
Have same value, but occur earlier than tested pair. This prevents duplicates.
Read here more about used Array methods: filter, some.
Assuming the array as defined in the original question, which is sorted to have each grouping together...
Completely untested code:
var reduced = [];
var groupName = '';
var groupMax;
var groupIndex;
var l = multiple.length; // Grab the array length only once
for (var i = 0; i < l; i++){
// Current Group Name doesn't match last Group Name
if (multiple[i][0] !== groupName) {
// Last Group Name is not empty (it's not the first Group)
if (groupName !== '') {
// Assume groupIndex has been set and grab the item
reduced.push(multiple[groupIndex]);
}
// Grab the new Group Name and set the initial Max and Index
groupName = multiple[i][0];
groupMax = multiple[i][1];
groupIndex = i;
}
// Current Value is bigger than last captured Group Max
if (multiple[i][1] > groupMax) {
// Grab the new Group Max and the current Index
groupMax = multiple[i][1];
groupIndex = i;
}
}
// Grab the last index, since there's no new group after the last item
reduced.push(multiple[groupIndex]);
There could be some syntax or logic errors. I didn't actually run this code, but I think the concept is correct.
Here's a tested version using a map to collect all the unique values, then the output is sorted by month/year and is independent of the order of the input data. This also works in all browsers (IE6+).
Working demo: http://jsfiddle.net/jfriend00/dk1tc73s/
function findLargest(list) {
var map = {}, output = [], item, key, val, current;
for (var i = 0; i < list.length; i++) {
item = list[i];
key = item[0];
val = item[1];
current = map[key];
if (current) {
// this date is in the map, so make sure to save the largest
// value for this date
if (val > current) {
map[key] = val;
}
} else {
// this date is not yet in the map, so add it
map[key] = val;
}
}
// map contains all the largest values, output it to an array
// the map is not in a guaranteed order
for (var key in map) {
output.push([key, map[key]])
}
// actually parse to numbers in sort so the comparison
// works properly on number strings of different lengths
function parseDate(str) {
var split = str.split("/");
return {m: +split[0], y: +split[1]};
}
// now sort the output
output.sort(function(t1, t2) {
var diffYear, a, b;
a = parseDate(t1[0]);
b = parseDate(t2[0]);
diffYear = a.y - b.y;
if (diffYear !== 0) {
return diffYear;
} else {
return a.m - b.m;
}
});
return output;
}

Categories

Resources