Common values in multiple variable lenght javascript arrays - javascript

I have 7 arrays in javascript and I need to find values that are present in all of them.
I don't think I'm the first one to ask this but I can't find a solution for this. I read many answers but they all compare only 2 arrays and that logic don't work for multiple arrays.
I tried functions proposed in Simplest code for array intersection in javascript but they don't fit the kind of arrays I have.
The arrays I have can have different lengths in elements and the element's lengtt can vary too. I also may have zero item arrays in which they should not be compared against.
The main problem is with different number lengths. All functions I tried require sorting but this causes a problem.
Given this arrays:
xnombre = [1,2,3,4,5,24,44,124,125,165];
xacomp = [1,5,44,55,124];
xeje = [];
xanio = [1,5,44,55,124];
xini = [1,5,44,55,124];
xaporte = [1,5,44,55,122,123,124,144,155,166,245];
xpcia = [2,1,3,4,6,5,7,9,12,12,14,15,44,16,17,19,124];
The first to arrays are sorted to:
[1, 124, 125, 165, 2, 24, 3, 4, 44, 5]
[1, 124, 44, 5, 55]
Which when I "intersect" I only get [1,124] but 44 and 5 are missed.
Any help would be appreciated.
Thanks

The function from the other question works, but you have to sort your array numerically, not lexicographically, since you are working with numbers, not strings.
function sortNumber(a,b) {
return a - b;
}
var xnombre = [1,2,3,4,5,24,44,124,125,165];
var xacomp = [1,5,44,55,124];
xnombre.sort(sortNumber);
xacomp.sort(sortNumber);
DEMO
To apply this to multiple arrays, you could apply this function consecutively:
// var result = intersect(a, b, c, ...);
function intersect(var_args) {
// sort arrays here or beforehand
var target = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i].length > 0) {
target = intersection_safe(target, arguments[i]);
}
}
return target;
}

This requires some of the new array methods, but it produces your desired output.
function intersection() {
var arrs = Array.prototype.filter.call(arguments, function (a) {
return a.length > 0;
}).sort(function (a, b) { // sort the arrays, so that we test the shortest.
return a.length - b.length;
});
var rest = arrs.slice(1),
test = arrs[0];
return test.filter(function (x) { return rest.every(function (a) { return a.indexOf(x) !== -1; }); });
}
var xnombre = [1, 2, 3, 4, 5, 24, 44, 124, 125, 165],
xacomp = [1, 5, 44, 55, 124],
xeje = [],
xanio = [1, 5, 44, 55, 124],
xini = [1, 5, 44, 55, 124],
xaporte = [1, 5, 44, 55, 122, 123, 124, 144, 155, 166, 245],
xpcia = [2, 1, 3, 4, 6, 5, 7, 9, 12, 12, 14, 15, 44, 16, 17, 19, 124];
intersection(xnombre, xacomp, xeje, xanio, xini, xaporte, xpcia)
// => [1, 5, 44, 124]

I tried your problem with underscore.
var _ = require('underscore');
xnombre = [1,2,3,4,5,24,44,124,125,165];
xacomp = [1,5,44,55,124];
xeje = [];
xanio = [1,5,44,55,124];
xini = [1,5,44,55,124];
xaporte = [1,5,44,55,122,123,124,144,155,166,245];
xpcia = [2,1,3,4,6,5,7,9,12,12,14,15,44,16,17,19,124];
var result = _.intersection(xnombre,xacomp,xanio,xini,xaporte,xpcia);
console.log(result);
But as you see that I haven't given the empty array, so somehow you have to ignore empty array.
Fiddle

Related

Sorting an array by their ascending value within the array in JS

It's a bit of a tricky situation I'm in, but I have an array like this:
const nums = [32, -3, 62, 8, 121, -231, 62, 13];
and need to replace them by their corresponding ascending index. The above example should yield:
[4, 1, 5, 2, 7, 0, 6, 3]
The solution I've come up with is this: TS Playground
const nums = [32, -3, 62, 8, 121, -231, 62, 13];
const numsCopy = nums.map(e => e);
// Basic sorting
for (let i = 0; i < numsCopy.length; i++) {
for (let j = 0; j < numsCopy.length; j++) {
if (numsCopy[i] < numsCopy[j]) {
let t = numsCopy[j];
numsCopy[j] = numsCopy[i];
numsCopy[i] = t;
}
}
}
for (let i = 0; i < numsCopy.length; i++) {
let sortedValue = numsCopy[i];
nums[nums.indexOf(sortedValue)] = i;
}
Problems arise however when I change nums to include a value nums.length > n >= 0. The call nums.indexOf(...) may return a faulty result, as it may have already sorted an index, even though it exists somewhere in the array.
If you replace nums with these values, -231 will have an index of 2 for some reason...
const nums = [32, -3, 62, 7, 121, -231, 62, 13, 0];
> [5, 1, 6, 3, 8, 2, 7, 4, 0]
Is there a better approach to this problem, or a fix to my solution?
You could sort the indices by the value and create a new array with index values a sorted positions.
to get the wanted result call the sorting function again and you get the indices sorted by the index order.
const
sort = array => [...array.keys()].sort((a, b) => array[a] - array[b]),
fn = array => sort(sort(array));
console.log(...fn([32, -3, 62, 8, 121, -231, 62, 13])); // 4 1 5 2 7 0 6 3
console.log(...fn([-1, 3, 1, 0, 2, 9, -2, 7])); // 1 5 3 2 4 7 0 6
Copy the array, sort its values, get indexOf, and null the value in the sorted copy:
const sortIndicesByValue = array => {
const sorted = [...array].sort((a, b) => a - b);
return array.map(e => {
const i = sorted.indexOf(e);
sorted[i] = null;
return i;
})
}
console.log(...sortIndicesByValue([32, -3, 62, 8, 121, -231, 62, 13]));
console.log(...sortIndicesByValue([-1, 3, 0, 0, 2, 9, -2, 7]));

Javascript sort an array by biggest and lowest number [duplicate]

This question already has answers here:
JavaScript: Rearrange an array in order – largest, smallest, 2nd largest, 2nd smallest, 3rd largest, 3rd smallest,
(4 answers)
Closed 2 years ago.
I need help with the sorting as i am totally confused what to do. This is the example:
[1, 65, 3, 52, 48, 63, 31, -3, 18, 56] to [-3, 65, 1, 63, 3, 56, 18, 52, 31, 48].
The first element has to be the smallest, the second to be biggest, the third to be the second smallest element, the fourth to be the second biggest element.
What i have tried is:
function solve(arr) {
var lowestNum = [...arr].sort((a,b) => a-b);
let biggestNum = [...arr].sort((a,b) => b-a);
let nums = [];
let i = 0;
while (nums.length !== arr.length) {
nums.push(lowestNum.shift()); lowestNum.pop();
nums.push(biggestNum.shift()); biggestNum.pop();
i++;
}
return nums;
}
console.log(solve([1, 65, 3, 52, 48, 63, 31, -3, 18, 56]));
However, that is not the way as my exercise requires me to sort.
This isnt the most elegant solution, but:
let a = [11, 2, 3, -22, 41];
function bigSmallSorter(arr) {
// Sort a copy of the passed in array from least to most.
let sortedArr = [...arr.sort((n, k) => n - k)];
let newArr = [];
let flip = true;
for( let i of arr ) {
let temp = flip
// Take first element of the sorted array
? sortedArr.shift()
// Take the last element of the sorted array
: sortedArr.pop();
// Add the newest value to the value that is ultimately returned
newArr.push(temp);
// Flip this so the next iteration takes from the other
// end of the array
flip = !flip;
}
// Profit
return newArr;
}
console.log(bigSmallSorter(a))
//>[ -22, 41, 2, 11, 3 ]
And an version of the method without comments:
let a = [11, 2, 3, -22, 41];
function bigSmallSorter(arr) {
let sortedArr = [...arr.sort((n, k) => n - k)]
let newArr = [];
let flip = true;
for( let i of arr ) {
let temp = flip
? sortedArr.shift()
: sortedArr.pop()
newArr.push(temp)
flip = !flip;
}
return newArr;
}
console.log(bigSmallSorter(a))

Add a random and not existing item to array from another array

Let's assume we have an array of items:
const arr1 = [22, 54, 67, 11, ...so on]
and empty one:
let arr2 = []
I can add random item with:
arr2 = [...arr2, arr1[Math.floor(Math.random()*arr1.length)]]
BUT how can I add a random item from first array to 2nd and already added should not be added?
Yes, we can keep added indexes in some tmp variable, but it doesnt seems right and I think there should be a different solution.
NOTE: array spreads because I need to add an item with some events.
For example user click to button and new item will be added to 2nd array, and this array may contain already added elems
You can create your custom logic to push the random value in arr2 so that the condition is that the numbers must be unique in arr2 and it will have maximum random numbers till the length of arr1:
const arr1 = [27, 54, 67, 11, 15, 22, 26, 58, 45, 87];
let arr2 = [];
function getRandom(){
var randomNumber = arr1[Math.floor(Math.random()*arr1.length)];
while(arr2.indexOf(randomNumber) !== -1 && arr2.length !== arr1.length) {
randomNumber = arr1[Math.floor(Math.random()*arr1.length)];
}
arr2.push(randomNumber);
}
getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom(); getRandom();getRandom();
console.log(arr2);
I think you are looking for something like this:
const arr1 = [22, 54, 67, 11, 23, 56, 43, 77, 34, 76, 30]
let arr2 = []
function addRandom() {
if(new Set(arr1).size === arr2.length) return; //prevention from infinite loop
// if(arr1.length=== arr2.length) return; // if arr1 doesn't contain duplicates
let random = arr1[Math.floor(Math.random()*arr1.length)];
if (!arr2.includes(random)) {
arr2.push(random);
} else {
addRandom();
}
}
addRandom();
console.log(arr2);
addRandom();
console.log(arr2);
addRandom();
console.log(arr2);
If you are sure that arr1 wont contain duplicates then replace (new Set(arr1).size === arr2.length) with arr1.length=== arr2.length.
If this is ok to mutate arr1 (as Matt Burland suggested in comments), try this:
arr2 = [...arr2, ...arr1.splice(Math.floor(Math.random()*arr1.length), 1]);
splice will remove the item from arr1 and return you the item removed, ready to be added in arr2!
If you cannot change it, just make a clone before using this line!
Hoping this will help you :)
If compatibility is not an issue you can use array set.
var arr1 = [44, 55, 100];
var arr2 = [44, 55, 100];
var arr3 = [...new Set(arr1, arr2)];
Something like this should work
let arr1 = [22,43,67,11,63];
let indexes = [...arr1.keys()];
indexes = indexes.sort(() => Math.Random() - 0.5);
let arr2 = [];
arr2 = [...arr2, arr1[indexes.pop()]]
This lets you preserve the original order of your first array too.
You could use the include function on your second array and check if the element you are trying to add does not exists.
let randomItem = arr1[Math.floor(Math.random()*arr1.length)];
while(arra2.includes(randomItem)) {
randomItem = arr1[Math.floor(Math.random()*arr1.length)];
}
arr2.push(randomItem);
#WebArtisan, you can also try the below code.
// Function that returns a randomly selected unique list of items from another
// array with duplicated items
function getUniqueRandomItems(arr1) {
let arr2 = [];
while(arr1.length) {
// A random number in range [0, arr1.length-1]
randomIndex = Math.floor((Math.random() * (arr1.length)) + 1) - 1;
// Removing 1 item from random index in range
removedItem = arr1.splice(randomIndex, 1)[0];
// If removedItem does not exist then add it to arr1
if(arr2.indexOf(removedItem) < 0) {
arr2.push(removedItem);
}
}
return arr2 // Return the result array with unique random items
}
/************ TEST 1****************************************/
const arr1 = [22, 54, 67, 11, 54, 22, 67, 11, 88, 90, 54, 2, 3, 2, 11, 54, 0];
const arr2 = getUniqueRandomItems(arr1);
console.log(arr2); // [ 2, 22, 88, 67, 54, 11, 3, 90, 0 ]
/************ TEST 2****************************************/
const arr3 = [1, 5, 2, 5, 1, 3, 3, 6, 3, 1, 9, 8, 10, 9, 7, 4, 3, 4, 2, 1, 10];
const arr4 = getUniqueRandomItems(arr3);
console.log(arr4); // [ 1, 7, 9, 10, 5, 3, 2, 8, 4, 6 ]

Comparing two arrays to return true if there is at least one in both arrays [duplicate]

This question already has answers here:
What is the fastest or most elegant way to compute a set difference using Javascript arrays?
(14 answers)
Closed 6 years ago.
I am writing an Ionic app - so this is in Angular 1.x
I have two arrays of numbers:
var arr1 = [1,32,423,43,23,64,232,5,67,54];
var arr2 = [11,32,1423,143,123,64,2232,35,467,594];
There are two common numbers in the array 32, and 64.
I want some JavaScript to efficiently return true if there is at least 1 common number in the 2 arrays.
I have the following code
angular.forEach(arr1 , function (arr1 , count) {
if ( inArray(arr1 , arr2) )
{
return true;
}
});
This is trivial to do with ES6:
var arr1 = [1, 32, 423, 43, 23, 64, 232, 5, 67, 54];
var arr2 = [11, 32, 1423, 143, 123, 64, 2232, 35, 467, 594];
console.log(arr1.some(i => arr2.includes(i)));
var arr1 = [1, 32, 423, 43, 23, 64, 232, 5, 67, 54];
var arr2 = [11, 32, 1423, 143, 123, 64, 2232, 35, 467, 594];
function hasCommonNumbers(arr1, arr2) {
let found = false;
for (let i = 0; i < arr1.length; i++) {
if (arr2.indexOf(arr1[i]) !== -1) {
found = true;
break;
}
}
return found;
}
console.log(hasCommonNumbers(arr1,arr2));
MDN some - stops looking when it finds a match, returns boolean
MDN includes - returns boolean to state if item is in array
var arr1 = [1,32,423,43,23,64,232,5,67,54];
var arr2 = [11,32,1423,143,123,64,2232,35,467,594];
var hasDupe = arr1.some(function(val){
return arr2.includes(val);
});
console.log(hasDupe);

Compare an unspecified number of arrays for common values in javascript

I would like to know how to compare two or more -- potentially unlimited -- arrays for common values and push these values into a new array efficiently. Below I have a function that will accept unlimited arguments, but I am uncertain if this is a good place to begin. PHP appears to have a method that can do what I want called array_intersect. Does javascript offer something similar?
Note: I have found examples of how this can be done with two or so arrays, but I have not found examples of how such approaches might be applied to an unspecified number of arrays as of yet. Therefore I do not see this as a duplicate question.
To further clarify, the arrays might be filled with anything. Letters, numbers, symbols, words, you name it, it might be there.
var sampleOne = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var sampleTwo = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
function FindDirectRelation() {
for(var i = 0; i < arguments.length; ++i) {
console.log(arguments[i]);
};
};
var directRelation = FindDirectRelation(sampleOne, sampleTwo);
I am still a coding novice, so please ensure that everything is explained in a way that is simple enough for me to understand.
using an existing intersect that works with 2 arrays, we can chain together a common sub-set using the built-in reduce() method on an array of arrays that need intersected:
function intersect(a, b) {
var aa = {};
a.forEach(function(v) { aa[v]=1; });
return b.filter(function(v) { return v in aa; });
}
var r1=[1,2,3],
r2=[1,3,4,5],
r3=[5,1,3];
alert([r1, r2, r3].reduce(intersect)) // shows: 1,3
if you define "intersect" as just being in more than one array (not every), then it's more complex...
Check to make sure the elements in the first array are also in the remaining arrays:
function multi_intersect(a) {
var other_arrays = Array.prototype.slice.call(arguments, 1);
return a . filter(function(elt) {
return other_arrays.every(function(an) {
return an.indexOf(elt) !== -1;
});
});
}
Try using Array.prototype.filter() , Array.prototype.indexOf()
var res = sampleOne.filter(function(val) {return sampleTwo.indexOf(val) !== -1})
var sampleOne = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var sampleTwo = [5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18];
var arr = ["a", "b", "c"];
var arr1 = ["c", "d", "e"];
var arr2 = [2, 7];
function samples() {
var args = Array.prototype.slice.call(arguments);
var res = [];
for (var i = 0, curr, next; i < args.length; i++) {
if (args[i + 1]) {
// set `curr` to array `i`
curr = args[i];
// set `next` to array `i + 1` if it exists
next = args[i + 1]
} else {
// if at last index, set `curr` to `args` : input arrays
// flattened to single array , with element at `i` removed
curr = [].concat.apply([], args.slice(0, args.length - 1));
console.log(curr)
// set next to current index
next = args[i];
};
next = next.filter(function(val) {
return curr.indexOf(val) !== -1
// filter duplicate entries at `res`
&& res.indexOf(val) === -1
});
res = res.concat.apply(res, next);
};
return res
}
var sample = samples(sampleOne, sampleTwo, arr, arr1, arr2);
console.log(sample); // [5, 6, 7, 8, 9, 10, 11, 12, "c", 2]

Categories