Merge Arrays in Javascript / Node.js - javascript

I was wondering if there was a way to merge arrays in this way in javascript
Array1 = ['1', '234', '56']
Array2 = ['1', '2', '45', '56']
Wanted outcome = ['11', '2342', '5645', '56']
Is there a way built into the language to do this?

Use .map to transform one array into another:
const Array1 = ['1', '234', '56']
const Array2 = ['1', '2', '45', '56'];
const merged = Array2.map((arr2elm, i) => (Array1[i] ? Array1[i] : '') + arr2elm);
console.log(merged);

An alternative using the function Array.from
The function Array.from accepts three params:
arrayLike An array-like or iterable object to convert to an array.
mapFn Map function to call on every element of the array.
Optional.
thisArg Value to use as this when executing mapFn Optional.
This approach passes an object with the required property length (array-like or iterable object) with the max length from both arrays and the callback will provide two params:
value (in this case is undefined) from an array
The current index.
Basically, the callback concatenates two values and both operands check for the current value at a specific index because not necessarily the arrays have the same length.
var arr1 = ['1', '234', '56'],
arr2 = ['1', '2', '45', '56'],
newArray = Array.from({length: Math.max(arr1.length, arr2.length)},
(_, i) => ((arr1[i] || '') + (arr2[i] || '')));
// ^ ^
// | |
// | +---- This is the current index.
// |
// +---- In this case, the value is undefined
// and is unnecessary to accomplish your
// scenario.
console.log(newArray);

No native feature for that, but here is a way to achieve it;
var a1 = ['1', '234', '56'];
var a2 = ['1', '2', '45', '56'];
var length = Math.max(a1.length, a2.length)
var merge = new Array(length).fill().map((el, index) => {
return (a1[index] || '') + (a2[index] || '')
})
console.log(merge)
This code will provide you with the correct answer regardless of which array is bigger.
EDIT:
As per commenter suggestion, by using a for loop you wont waste memory resources by creating an array just for iteration purposes.
var a1 = ['1', '234', '56'];
var a2 = ['1', '2', '45', '56'];
var length = Math.max(a1.length, a2.length)
var merge = []
for (var i = 0; i < length; i++) {
merge.push((a1[i] || '') + (a2[i] || ''))
}
console.log(merge)
And, even faster if you replace the .push() with an assignment:
var a1 = ['1', '234', '56'];
var a2 = ['1', '2', '45', '56'];
var length = Math.max(a1.length, a2.length);
var merge = new Array(length);
for (var i = 0; i < length; i++) {
merge[i] = (a1[i] || '') + (a2[i] || '');
}
console.log(merge);

function mergeArrays(array1, array2) {
const count = array1.length > array2.length
? array1.length
: array2.length;
const result = [];
for (let i = 0; i < count; i++) {
result.push(`${ array1[i] || '' }${ array2[i] || '' }`);
}
return result;
}
A side-note: don't use uppercase naming for your identifiers unless they are classes.

You can do like below
let Array1 = ['1', '234', '56','11','11','22'];
let Array2 = ['1', '2', '45', '56'];
let new_arr=[];
new_arr=Array1.map((object,i) => object + Array2[i]).concat(Array2.splice(Array1.length,1));
//remove undefined due to variable size
let new_arr_str=new_arr.join(",").replace(/undefined/g,'');
console.log(new_arr_str.split(","));
I have removed undefined variable if array1 is larger than array 1 using string functions

Related

Can I use Array.prototype.some() to check if two arrays have two common elements? [duplicate]

I have a target array ["apple","banana","orange"], and I want to check if other arrays contain any one of the target array elements.
For example:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
How can I do it in JavaScript?
Vanilla JS
ES2016:
const found = arr1.some(r=> arr2.includes(r))
ES6:
const found = arr1.some(r=> arr2.indexOf(r) >= 0)
How it works
some(..) checks each element of the array against a test function and returns true if any element of the array passes the test function, otherwise, it returns false. indexOf(..) >= 0 and includes(..) both return true if the given argument is present in the array.
vanilla js
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
var findOne = function (haystack, arr) {
return arr.some(function (v) {
return haystack.indexOf(v) >= 0;
});
};
As noted by #loganfsmyth you can shorten it in ES2016 to
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
const findOne = (haystack, arr) => {
return arr.some(v => haystack.includes(v));
};
or simply as arr.some(v => haystack.includes(v));
If you want to determine if the array has all the items from the other array, replace some() to every()
or as arr.every(v => haystack.includes(v));
ES6 solution:
let arr1 = [1, 2, 3];
let arr2 = [2, 3];
let isFounded = arr1.some( ai => arr2.includes(ai) );
Unlike of it: Must contains all values.
let allFounded = arr2.every( ai => arr1.includes(ai) );
Hope, will be helpful.
If you're not opposed to using a libray, http://underscorejs.org/ has an intersection method, which can simplify this:
var _ = require('underscore');
var target = [ 'apple', 'orange', 'banana'];
var fruit2 = [ 'apple', 'orange', 'mango'];
var fruit3 = [ 'mango', 'lemon', 'pineapple'];
var fruit4 = [ 'orange', 'lemon', 'grapes'];
console.log(_.intersection(target, fruit2)); //returns [apple, orange]
console.log(_.intersection(target, fruit3)); //returns []
console.log(_.intersection(target, fruit4)); //returns [orange]
The intersection function will return a new array with the items that it matched and if not matches it returns empty array.
ES6 (fastest)
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)
ES2016
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v => b.includes(v));
Underscore
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
_.intersection(a, b)
DEMO: https://jsfiddle.net/r257wuv5/
jsPerf: https://jsperf.com/array-contains-any-element-of-another-array
If you don't need type coercion (because of the use of indexOf), you could try something like the following:
var arr = [1, 2, 3];
var check = [3, 4];
var found = false;
for (var i = 0; i < check.length; i++) {
if (arr.indexOf(check[i]) > -1) {
found = true;
break;
}
}
console.log(found);
Where arr contains the target items. At the end, found will show if the second array had at least one match against the target.
Of course, you can swap out numbers for anything you want to use - strings are fine, like your example.
And in my specific example, the result should be true because the second array's 3 exists in the target.
UPDATE:
Here's how I'd organize it into a function (with some minor changes from before):
var anyMatchInArray = (function () {
"use strict";
var targetArray, func;
targetArray = ["apple", "banana", "orange"];
func = function (checkerArray) {
var found = false;
for (var i = 0, j = checkerArray.length; !found && i < j; i++) {
if (targetArray.indexOf(checkerArray[i]) > -1) {
found = true;
}
}
return found;
};
return func;
}());
DEMO: http://jsfiddle.net/u8Bzt/
In this case, the function could be modified to have targetArray be passed in as an argument instead of hardcoded in the closure.
UPDATE2:
While my solution above may work and be (hopefully more) readable, I believe the "better" way to handle the concept I described is to do something a little differently. The "problem" with the above solution is that the indexOf inside the loop causes the target array to be looped over completely for every item in the other array. This can easily be "fixed" by using a "lookup" (a map...a JavaScript object literal). This allows two simple loops, over each array. Here's an example:
var anyMatchInArray = function (target, toMatch) {
"use strict";
var found, targetMap, i, j, cur;
found = false;
targetMap = {};
// Put all values in the `target` array into a map, where
// the keys are the values from the array
for (i = 0, j = target.length; i < j; i++) {
cur = target[i];
targetMap[cur] = true;
}
// Loop over all items in the `toMatch` array and see if any of
// their values are in the map from before
for (i = 0, j = toMatch.length; !found && (i < j); i++) {
cur = toMatch[i];
found = !!targetMap[cur];
// If found, `targetMap[cur]` will return true, otherwise it
// will return `undefined`...that's what the `!!` is for
}
return found;
};
DEMO: http://jsfiddle.net/5Lv9v/
The downside to this solution is that only numbers and strings (and booleans) can be used (correctly), because the values are (implicitly) converted to strings and set as the keys to the lookup map. This isn't exactly good/possible/easily done for non-literal values.
Using filter/indexOf:
function containsAny(source,target)
{
var result = source.filter(function(item){ return target.indexOf(item) > -1});
return (result.length > 0);
}
//results
var fruits = ["apple","banana","orange"];
console.log(containsAny(fruits,["apple","grape"]));
console.log(containsAny(fruits,["apple","banana","pineapple"]));
console.log(containsAny(fruits,["grape", "pineapple"]));
You could use lodash and do:
_.intersection(originalTarget, arrayToCheck).length > 0
Set intersection is done on both collections producing an array of identical elements.
const areCommonElements = (arr1, arr2) => {
const arr2Set = new Set(arr2);
return arr1.some(el => arr2Set.has(el));
};
Or you can even have a better performance if you first find out which of these two arrays is longer and making Set out for the longest array, while applying some method on the shortest one:
const areCommonElements = (arr1, arr2) => {
const [shortArr, longArr] = (arr1.length < arr2.length) ? [arr1, arr2] : [arr2, arr1];
const longArrSet = new Set(longArr);
return shortArr.some(el => longArrSet.has(el));
};
I wrote 3 solutions. Essentially they do the same. They return true as soon as they get true. I wrote the 3 solutions just for showing 3 different way to do things. Now, it depends what you like more. You can use performance.now() to check the performance of one solution or the other. In my solutions I'm also checking which array is the biggest and which one is the smallest to make the operations more efficient.
The 3rd solution may not be the cutest but is efficient. I decided to add it because in some coding interviews you are not allowed to use built-in methods.
Lastly, sure...we can come up with a solution with 2 NESTED for loops (the brute force way) but you want to avoid that because the time complexity is bad O(n^2).
Note:
instead of using .includes() like some other people did, you can use
.indexOf(). if you do just check if the value is bigger than 0. If
the value doesn't exist will give you -1. if it does exist, it will give you
greater than 0.
indexOf() vs includes()
Which one has better performance? indexOf() for a little bit, but includes is more readable in my opinion.
If I'm not mistaken .includes() and indexOf() use loops behind the scene, so you will be at O(n^2) when using them with .some().
USING loop
const compareArraysWithIncludes = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
return bigArray.includes(smallArray[i]);
}
return false;
};
USING .some()
const compareArraysWithSome = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
return smallArray.some(c => bigArray.includes(c));
};
USING MAPS Time complexity O(2n)=>O(n)
const compararArraysUsingObjs = (arr1, arr2) => {
const map = {};
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
if (!map[smallArray[i]]) {
map[smallArray[i]] = true;
}
}
for (let i = 0; i < bigArray.length; i++) {
if (map[bigArray[i]]) {
return true;
}
}
return false;
};
Code in my:
stackblitz
I'm not an expert in performance nor BigO so if something that I said is wrong let me know.
You can use a nested Array.prototype.some call. This has the benefit that it will bail at the first match instead of other solutions that will run through the full nested loop.
eg.
var arr = [1, 2, 3];
var match = [2, 4];
var hasMatch = arr.some(a => match.some(m => a === m));
I found this short and sweet syntax to match all or some elements between two arrays. For example
// OR operation. find if any of array2 elements exists in array1. This will return as soon as there is a first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];
console.log(array2.some(ele => array1.includes(ele)));
// prints TRUE
// AND operation. find if all of array2 elements exists in array1. This will return as soon as there is a no first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));
// prints FALSE
Hope that helps someone in future!
Just one more solution
var a1 = [1, 2, 3, 4, 5]
var a2 = [2, 4]
Check if a1 contain all element of a2
var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)
What about using a combination of some/findIndex and indexOf?
So something like this:
var array1 = ["apple","banana","orange"];
var array2 = ["grape", "pineapple"];
var found = array1.some(function(v) { return array2.indexOf(v) != -1; });
To make it more readable you could add this functionality to the Array object itself.
Array.prototype.indexOfAny = function (array) {
return this.findIndex(function(v) { return array.indexOf(v) != -1; });
}
Array.prototype.containsAny = function (array) {
return this.indexOfAny(array) != -1;
}
Note: If you'd want to do something with a predicate you could replace the inner indexOf with another findIndex and a predicate
Here is an interesting case I thought I should share.
Let's say that you have an array of objects and an array of selected filters.
let arr = [
{ id: 'x', tags: ['foo'] },
{ id: 'y', tags: ['foo', 'bar'] },
{ id: 'z', tags: ['baz'] }
];
const filters = ['foo'];
To apply the selected filters to this structure we can
if (filters.length > 0)
arr = arr.filter(obj =>
obj.tags.some(tag => filters.includes(tag))
);
// [
// { id: 'x', tags: ['foo'] },
// { id: 'y', tags: ['foo', 'bar'] }
// ]
Good perfomance solution:
We should transform one of arrays to object.
const contains = (arr1, mainObj) => arr1.some(el => el in mainObj);
const includes = (arr1, mainObj) => arr1.every(el => el in mainObj);
Usage:
const mainList = ["apple", "banana", "orange"];
// We make object from array, you can use your solution to make it
const main = Object.fromEntries(mainList.map(key => [key, true]));
contains(["apple","grape"], main) // => true
contains(["apple","banana","pineapple"], main) // => true
contains(["grape", "pineapple"], main) // => false
includes(["apple", "grape"], main) // => false
includes(["banana", "apple"], main) // => true
you can face with some disadvantage of checking by in operator (eg 'toString' in {} // => true), so you can change solution to obj[key] checker
Adding to Array Prototype
Disclaimer: Many would strongly advise against this. The only time it'd really be a problem was if a library added a prototype function with the same name (that behaved differently) or something like that.
Code:
Array.prototype.containsAny = function(arr) {
return this.some(
(v) => (arr.indexOf(v) >= 0)
)
}
Without using big arrow functions:
Array.prototype.containsAny = function(arr) {
return this.some(function (v) {
return arr.indexOf(v) >= 0
})
}
Usage
var a = ["a","b"]
console.log(a.containsAny(["b","z"])) // Outputs true
console.log(a.containsAny(["z"])) // Outputs false
My solution applies Array.prototype.some() and Array.prototype.includes() array helpers which do their job pretty efficient as well
ES6
const originalFruits = ["apple","banana","orange"];
const fruits1 = ["apple","banana","pineapple"];
const fruits2 = ["grape", "pineapple"];
const commonFruits = (myFruitsArr, otherFruitsArr) => {
return myFruitsArr.some(fruit => otherFruitsArr.includes(fruit))
}
console.log(commonFruits(originalFruits, fruits1)) //returns true;
console.log(commonFruits(originalFruits, fruits2)) //returns false;
When I looked at your answers, I could not find the answer I wanted.
I did something myself and I want to share this with you.
It will be true only if the words entered (array) are correct.
function contains(a,b) {
let counter = 0;
for(var i = 0; i < b.length; i++) {;
if(a.includes(b[i])) counter++;
}
if(counter === b.length) return true;
return false;
}
let main_array = ['foo','bar','baz'];
let sub_array_a = ['foo','foobar'];
let sub_array_b = ['foo','bar'];
console.log(contains(main_array, sub_array_a)); // returns false
console.log(contains(main_array,sub_array_b )); // returns true
Array .filter() with a nested call to .find() will return all elements in the first array that are members of the second array. Check the length of the returned array to determine if any of the second array were in the first array.
getCommonItems(firstArray, secondArray) {
return firstArray.filter((firstArrayItem) => {
return secondArray.find((secondArrayItem) => {
return firstArrayItem === secondArrayItem;
});
});
}
It can be done by simply iterating across the main array and check whether other array contains any of the target element or not.
Try this:
function Check(A) {
var myarr = ["apple", "banana", "orange"];
var i, j;
var totalmatches = 0;
for (i = 0; i < myarr.length; i++) {
for (j = 0; j < A.length; ++j) {
if (myarr[i] == A[j]) {
totalmatches++;
}
}
}
if (totalmatches > 0) {
return true;
} else {
return false;
}
}
var fruits1 = new Array("apple", "grape");
alert(Check(fruits1));
var fruits2 = new Array("apple", "banana", "pineapple");
alert(Check(fruits2));
var fruits3 = new Array("grape", "pineapple");
alert(Check(fruits3));
DEMO at JSFIDDLE
Not sure how efficient this might be in terms of performance, but this is what I use using array destructuring to keep everything nice and short:
const shareElements = (arr1, arr2) => {
const typeArr = [...arr1, ...arr2]
const typeSet = new Set(typeArr)
return typeArr.length > typeSet.size
}
Since sets cannot have duplicate elements while arrays can, combining both input arrays, converting it to a set, and comparing the set size and array length would tell you if they share any elements.
With underscorejs
var a1 = [1,2,3];
var a2 = [1,2];
_.every(a1, function(e){ return _.include(a2, e); } ); //=> false
_.every(a2, function(e){ return _.include(a1, e); } ); //=> true
Vanilla JS with partial matching & case insensitive
The problem with some previous approaches is that they require an exact match of every word. But, What if you want to provide results for partial matches?
function search(arrayToSearch, wordsToSearch) {
arrayToSearch.filter(v =>
wordsToSearch.every(w =>
v.toLowerCase().split(" ").
reduce((isIn, h) => isIn || String(h).indexOf(w) >= 0, false)
)
)
}
//Usage
var myArray = ["Attach tag", "Attaching tags", "Blah blah blah"];
var searchText = "Tag attach";
var searchArr = searchText.toLowerCase().split(" "); //["tag", "attach"]
var matches = search(myArray, searchArr);
//Will return
//["Attach tag", "Attaching tags"]
This is useful when you want to provide a search box where users type words and the results can have those words in any order, position and case.
Update #Paul Grimshaw answer, use includes insteed of indexOf for more readable
let found = arr1.some(r=> arr2.indexOf(r) >= 0)
let found = arr1.some(r=> arr2.includes(r))
A short way of writing this:
const found = arr1.some(arr2.includes)
I came up with a solution in node using underscore js like this:
var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) {
next();
}
You are looking for intersection between the two arrays. And you have two major intersection types: 'every' and 'some'. Let me give you good examples:
EVERY
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia'];
// Find 'every' brand intersection.
// Meaning all elements inside 'brands2' must be present in 'brands1':
let intersectionEvery = brands2.every( brand => brands1.includes(brand) );
if (intersectionEvery) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
If condition is not met (like if you put 'Mercedes' in brands2) then 'intersectionEvery' won't be satisfied - will be bool false.
If condition is met it will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common list.
Sandbox: https://jsfiddle.net/bqmg14t6/
SOME
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia', 'Mercedes', 'Land Rover'];
// Find 'some' brand intersection.
// Meaning some elements inside 'brands2' must be also present in 'brands1':
let intersectionSome = brands2.some( brand => brands1.includes(brand) );
if (intersectionSome) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
Here we are looking for some common brands, not necessarily all.
It will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common brands.
Sandbox: https://jsfiddle.net/zkq9j3Lh/
Personally, I would use the following function:
var arrayContains = function(array, toMatch) {
var arrayAsString = array.toString();
return (arrayAsString.indexOf(','+toMatch+',') >-1);
}
The "toString()" method will always use commas to separate the values. Will only really work with primitive types.
console.log("searching Array: "+finding_array);
console.log("searching in:"+reference_array);
var check_match_counter = 0;
for (var j = finding_array.length - 1; j >= 0; j--)
{
if(reference_array.indexOf(finding_array[j]) > 0)
{
check_match_counter = check_match_counter + 1;
}
}
var match = (check_match_counter > 0) ? true : false;
console.log("Final result:"+match);

JS function to compare two arrays of numbers that include duplicates

I'm building a mastermind game. In this game the player needs to guess a secret random number. To make this work I need to have a function that can compare the two arrays and check if there is a match in number and position and/or a match only in the number but not the position.
The problem: This function works well for the most part when there are not repeated numbers in the arrays, but gives me a wrong output when there are repeated numbers.
example:
Random -- arr1 = ['5', '5', '3', '4']
Guess -- arr 2 = ['5', '1', '0', '0,]
expected result
{match: true, exactMatches: 1, matchesByValue: 0}
I'm getting this wrong result:
{match: true, exactMatches: 1, matchesByValue: 1}
Important: matchesByValue means correct number in wrong position. It shouldn't consider numbers that have been already counted as exactMatches.
function compareGuessVsRandom(arr1, arr2) {
// convert the arrays to sets
const set1 = new Set(arr1);
const set2 = new Set(arr2);
let exactMatches = 0;
let matchesByValue = 0;
// check if each value in the first array has the same value and position in the second array
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] == arr2[i]) {
exactMatches++;
} else if (set1.has(arr2[i])) {
matchesByValue++;
}
}
// if all checks pass, the arrays are a match
const result = {
match: true,
exactMatches: exactMatches,
matchesByValue: matchesByValue,
};
console.log(result);
return result;
}
function compareGuessVsRandom (arr1, arr2) {
// The list of all the indicies at which there is an exact match
const exactMatchesList = []
// The amount of matche by value
let matchesByValue = 0
for (let i = 0; i < arr1.length; i++)
if (arr1[i] === arr2[i])
exactMatchesList.push(i)
// Init sets with arrays without the exactly-matched values
const set1 = new Set(arr1.filter((_, i) => !exactMatchesList.includes(i)))
const set2 = new Set(arr2.filter((_, i) => !exactMatchesList.includes(i)))
// If set2 contains an element of set1, increment matchesByValue
for (const e of set1)
matchesByValue += set2.has(e)
// Get the amount of exact matches
const exactMatches = exactMatchesList.length
const result = {
match: exactMatches !== 0 || matchesByValue !== 0,
exactMatches,
matchesByValue
}
return result;
}
const random = [ '5', '5', '3', '4' ]
const guess = [ '5', '1', '0', '0' ]
console.log(compareGuessVsRandom(random, guess))
The has method returns true if set1 contains the specified element. So regardless of whether an exact match has occurred or not, it will increment 'matchesByValue' even for a match at the index with the exact match.
For example, in a scenario where arr2 has [5,5,0,0]. The first '5'. will increment 'exactMatches' but the second one will also increment 'matchesByValue' by matching it with index 0 of set1.
You can eliminate duplicate matches by comparing indexes of the two types of matches.
This function solved the problem with duplicates. Thanks everyone!
//helper function to count how many values two arrays have in common
const countCommonValuesOfArrays = (arr1, arr2) =>
arr1.reduce((a, c) => a + arr2.includes(c), 0);
export function compareGuessVsRandom(guesses, random) {
//check for duplicates
let perfectMatch = [];
let equalValues = [];
let unmatchedGuesses = [];
let unmatchedRandom = [];
for (let i = 0; i < guesses.length; i++) {
if (guesses[i] === random[i]) {
perfectMatch++;
} else {
unmatchedGuesses.push(guesses[i]);
unmatchedRandom.push(random[i]);
}
}
equalValues = countCommonValuesOfArrays(unmatchedGuesses, unmatchedRandom);
return {
gameMatch: perfectMatch === random.length,
perfectMatch: perfectMatch,
equalValues: equalValues,
};
}

Filter an array in javascript with value 0

I got an array like this:
let arr = ['1','2','0','3','0',undefined,'0',undefined,'3','',''];
In order to filter the 'undefined' and '' element of this array and convert it to a number, I do like this:
arr = arr.filter(function(e){
if(e){
return parseInt(e);
}
});
I got:
[1,2,3,3]
The 0 has also been filtered because 'return 0' means 'return false';
I want to know how do you normally do with this kind of problem?
Update:
I saw the following answers propose many useful ways.
I learned a lot from it.
And if the element in the array need to be a number, not a string, should I traverse the array again? Or there is an alternative one-step method?
Replace
return parseInt(e);
with
return !isNaN(e);
Demo
var arr = ['1','2','0','3','0',undefined,'0',undefined,'3','',''];
var output = arr.filter(function(e){
if(e){
return !isNaN(e);
}
});
console.log( output );
Edit
For converting the values to Number as well, just add .map( Number ) to the filter output
Demo
var arr = ['1','2','0','3','0',undefined,'0',undefined,'3','',''];
var output = arr.filter(function(e){
if(e){
return !isNaN(e);
}
}).map( Number );
console.log( output );
You could chain the wanted conditions.
let array = ['1', '2', '0', '3', '0', undefined, '0', undefined, '3', '', ''];
array = array
.filter(Boolean) // get only truthy values
.map(Number); // convert all values to number
console.log(array);
It's easy with array chain-functions:
let arr = ['1', '2', '0', '3', '0', undefined, '0', undefined, '3', '', '']
// filter valid elements (undefined and '' evaluates to false)
.filter(e => e)
// to exclude '0' from the list, do a bitwise-or
//.filter(e => e|0)
// cast into numbers
.map(e => e * 1);
console.log(arr);
With slight change
let arr = ['1','2','0','3','0',undefined,'0',undefined,'3','',''];
arr = arr.filter(function(e){
if( parseInt(e) >=0 ){
return e;
}
});
console.log(arr);
let arr = ['1','2','0','3','0',undefined,'0',undefined,'3','',''];
let result = [];
for(let item of arr) {
let num = +item;
if(item === '' || Number.isNaN(num)) {
continue;
}
result.push(num);
}
console.log(result);
You can use RegExp.prototype.test() with RegExp /^\d+$/ to check if the value is one or more digits
arr = arr.filter(n => /^\d$/.test(n))
let arr = ['1','2','0','3','0',undefined,'0',undefined,'3','',''];
// map everything to Number (undefined becomes NaN)
// filter all valid numbers
arr = arr.map(Number).filter(e => !isNaN(e))
console.log(arr);

Sorting an array of strings and numbers while maintaining the array's original order

I just took a coding interview (ugh.) and I could not for the life of me figure this out.
Question:
Double Sort
Please write a javascript method which accepts an array of strings. Each element can either be a number ("165") or a word ("dog"). Your method should sort and return the array such that (1) The words are in alphabetical order and the numbers in numerical order, and (2) the order of words and numbers within the array is the same.
Examples (input => output):
sort(['5', '4', 'dog', '1', 'cat'])
=> ['1', '4', 'cat', '5', 'dog']
sort(['dog', 'cat'])
=> ['cat', 'dog']
sort('5', '3')
=> ['3', '5']
I was able to write a basic sort function that sorted the array alphabetically and numerically, but I was unable to maintain the array's original order. This was what I managed to come up with in the time limit:
var multiSortArray = [5, 4, 'dog', 1, 'cat'];
var multiSort = function(arr) {
var sortedArray = arr.sort();
console.log(sortedArray);
}
multiSort(multiSortArray);
which outputs: [1, 4, 5, "cat", "dog"]
Any help'd be appreciated, I'm irritated as hell I couldn't figure this out. All I could find in SO was ordering objects which I'm not sure is what I need to do (or maybe I do. I have no idea.)
Thanks everyone!
Just split the numbers and words into seperate arrays, sort them, and add back together again
function sort(arr) {
let n = arr.filter(x => isNaN(x)).sort((a,b) => a.localeCompare(b));
let c = arr.filter(y => !isNaN(y)).sort((a,b) => a-b);
return arr.map(z => (isNaN(z) ? n : c).shift());
}
console.log(sort(['5', '4', 'dog', '1', 'cat']));
One way to do it:
var arr = ['5', '4', 'dog', '1', 'cat'];
// STEP 1: split the original array into two arrays, one for strings and one for numbers
var str = [], num = [];
arr.forEach(e => isNaN(e)? str.push(e): num.push(e));
// STEP 2: sort the two arrays
str.sort();
num.sort((a, b) => a - b); // because the numbers are actually strings we need to do a - b to implicitly convert them into numbers and sort them using the substraction result
// STEP 3: for each element in the original array, if the original item was a string then replace it with the first item in the string array (and remove the added item), if the original item was a number, do the same with the num array
arr.forEach((e, i) => arr[i] = isNaN(e)? str.shift(): num.shift());
console.log(arr);
The first thing that would have come to my mind would have been to make a map of which type of thing was in which index, then separate and sort, then zip them together again according to the type:
function sort(a) {
const type = a.map(e => /^\d+$/.test(e));
const nums = a.filter((e, i) => type[i]).sort((left, right) => left - right);
const strs = a.filter((e, i) => !type[i]).sort((left, right) => left.localeCompare(right));
let nindex = 0, sindex = 0;
return type.map(t => t ? nums[nindex++] : strs[sindex++]);
}
console.log(sort(['5', '4', 'dog', '1', 'cat']));
// => ['1', '4', 'cat', '5', 'dog']
console.log(sort(['dog', 'cat']));
// => ['cat', 'dog']
console.log(sort(['5', '3']));
// => ['3', '5']
console.log(sort(['5', 'gazelle', '300']));
// => ['5', 'gazelle', '300']
function sort(a) {
const type = a.map(e => /^\d+$/.test(e));
const nums = a.filter((e, i) => type[i]).sort((left, right) => left - right);
const strs = a.filter((e, i) => !type[i]).sort((left, right) => left.localeCompare(right));
let nindex = 0, sindex = 0;
return type.map(t => t ? nums[nindex++] : strs[sindex++]);
}
.as-console-wrapper {
max-height: 100% !important;
}
Or with ES5 and earlier syntax:
console.log(sort(['5', '4', 'dog', '1', 'cat']));
// => ['1', '4', 'cat', '5', 'dog']
console.log(sort(['dog', 'cat']));
// => ['cat', 'dog']
console.log(sort(['5', '3']));
// => ['3', '5']
console.log(sort(['5', 'gazelle', '300']));
// => ['5', 'gazelle', '300']
function sort(a) {
var type = a.map(function(e) { return /^\d+$/.test(e); });
var nums = a.filter(function(e, i) { return type[i]; }).sort(function(left, right) {
return left - right;
});
var strs = a.filter(function(e, i) { return !type[i]; }).sort(function(left, right) {
return left.localeCompare(right);
});
var nindex = 0, sindex = 0;
return type.map(function(t) {
return t ? nums[nindex++] : strs[sindex++];
});
}
.as-console-wrapper {
max-height: 100% !important;
}
...but I'd've asked them a bunch of questions about the data, as I might go another way if there were hundreds of thousands of entries.
Also note ensuring a numeric comparison for the numbers, and a correct lexicographic comparison for the strings (within the browser's feature set, anyway).
Side note: In my version, I detected numbers like this: /^\d+$/.test(e). That only allows for integers, and doesn't allow for scientific notation. The alternative would be a variation on what adeneo did: e !== "" && !isNaN(e), which coerces e to a number if it's not blank and checks if the result was NaN (which would mean it couldn't be converted). The check for "" is because sadly, coercing "" to number gives you 0 and so just isNaN(e) would give an incorrect result for "".
This is a bit quick and not super efficient, but it's one potential solution that produces your output:
var sorter = function(array){
let chars = [];
let nums = [];
array.forEach( (v,i) => {
if(isNaN(+v)){
chars.push(i);
}
else{
nums.push(i);
}
});
let newArray = [];
let sortedChars = array.filter(a => isNaN(+a)).sort();
let sortedNums = array.filter(a => !isNaN(+a)).sort();
chars.forEach((value, index) => {
newArray[value] = sortedChars[index];
});
nums.forEach((value, index) => {
newArray[value] = sortedNums[index];
});
return newArray;
}
This could be easily done in many ways so you get your sorted array as
[1,4,5,'cat','dog']
So before sorting take another array of same size and make a mark
0 - means integer
1 - means string
So this new array would look like this
temp = [0, 0, 1, 0, 1];
Now after you have sorted just iterate over this and replace the 0 with incoming integers in order and 1 with strings
And you will get the required output.
You could use an object for the typed values and sort accordingly. Then use the original array again and map the values ot the same type for the result set.
function sort(array) {
var order = {
number: function (a, b) { return a - b; },
string: function (a, b) { return a.localeCompare(b); },
default: function () { return 0; },
};
temp = {};
array.forEach(function (a) { (temp[typeof a] = temp[typeof a] || []).push(a); });
Object.keys(temp).forEach(function (t) { temp[t].sort(order[t] || order.default); });
return array.map(function (a) { return temp[typeof a].shift(); });
};
console.log(sort([5, 4, 'dog', 1, 'cat']));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Check if an array contains any element of another array in JavaScript

I have a target array ["apple","banana","orange"], and I want to check if other arrays contain any one of the target array elements.
For example:
["apple","grape"] //returns true;
["apple","banana","pineapple"] //returns true;
["grape", "pineapple"] //returns false;
How can I do it in JavaScript?
Vanilla JS
ES2016:
const found = arr1.some(r=> arr2.includes(r))
ES6:
const found = arr1.some(r=> arr2.indexOf(r) >= 0)
How it works
some(..) checks each element of the array against a test function and returns true if any element of the array passes the test function, otherwise, it returns false. indexOf(..) >= 0 and includes(..) both return true if the given argument is present in the array.
vanilla js
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
var findOne = function (haystack, arr) {
return arr.some(function (v) {
return haystack.indexOf(v) >= 0;
});
};
As noted by #loganfsmyth you can shorten it in ES2016 to
/**
* #description determine if an array contains one or more items from another array.
* #param {array} haystack the array to search.
* #param {array} arr the array providing items to check for in the haystack.
* #return {boolean} true|false if haystack contains at least one item from arr.
*/
const findOne = (haystack, arr) => {
return arr.some(v => haystack.includes(v));
};
or simply as arr.some(v => haystack.includes(v));
If you want to determine if the array has all the items from the other array, replace some() to every()
or as arr.every(v => haystack.includes(v));
ES6 solution:
let arr1 = [1, 2, 3];
let arr2 = [2, 3];
let isFounded = arr1.some( ai => arr2.includes(ai) );
Unlike of it: Must contains all values.
let allFounded = arr2.every( ai => arr1.includes(ai) );
Hope, will be helpful.
If you're not opposed to using a libray, http://underscorejs.org/ has an intersection method, which can simplify this:
var _ = require('underscore');
var target = [ 'apple', 'orange', 'banana'];
var fruit2 = [ 'apple', 'orange', 'mango'];
var fruit3 = [ 'mango', 'lemon', 'pineapple'];
var fruit4 = [ 'orange', 'lemon', 'grapes'];
console.log(_.intersection(target, fruit2)); //returns [apple, orange]
console.log(_.intersection(target, fruit3)); //returns []
console.log(_.intersection(target, fruit4)); //returns [orange]
The intersection function will return a new array with the items that it matched and if not matches it returns empty array.
ES6 (fastest)
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v=> b.indexOf(v) !== -1)
ES2016
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
a.some(v => b.includes(v));
Underscore
const a = ['a', 'b', 'c'];
const b = ['c', 'a', 'd'];
_.intersection(a, b)
DEMO: https://jsfiddle.net/r257wuv5/
jsPerf: https://jsperf.com/array-contains-any-element-of-another-array
If you don't need type coercion (because of the use of indexOf), you could try something like the following:
var arr = [1, 2, 3];
var check = [3, 4];
var found = false;
for (var i = 0; i < check.length; i++) {
if (arr.indexOf(check[i]) > -1) {
found = true;
break;
}
}
console.log(found);
Where arr contains the target items. At the end, found will show if the second array had at least one match against the target.
Of course, you can swap out numbers for anything you want to use - strings are fine, like your example.
And in my specific example, the result should be true because the second array's 3 exists in the target.
UPDATE:
Here's how I'd organize it into a function (with some minor changes from before):
var anyMatchInArray = (function () {
"use strict";
var targetArray, func;
targetArray = ["apple", "banana", "orange"];
func = function (checkerArray) {
var found = false;
for (var i = 0, j = checkerArray.length; !found && i < j; i++) {
if (targetArray.indexOf(checkerArray[i]) > -1) {
found = true;
}
}
return found;
};
return func;
}());
DEMO: http://jsfiddle.net/u8Bzt/
In this case, the function could be modified to have targetArray be passed in as an argument instead of hardcoded in the closure.
UPDATE2:
While my solution above may work and be (hopefully more) readable, I believe the "better" way to handle the concept I described is to do something a little differently. The "problem" with the above solution is that the indexOf inside the loop causes the target array to be looped over completely for every item in the other array. This can easily be "fixed" by using a "lookup" (a map...a JavaScript object literal). This allows two simple loops, over each array. Here's an example:
var anyMatchInArray = function (target, toMatch) {
"use strict";
var found, targetMap, i, j, cur;
found = false;
targetMap = {};
// Put all values in the `target` array into a map, where
// the keys are the values from the array
for (i = 0, j = target.length; i < j; i++) {
cur = target[i];
targetMap[cur] = true;
}
// Loop over all items in the `toMatch` array and see if any of
// their values are in the map from before
for (i = 0, j = toMatch.length; !found && (i < j); i++) {
cur = toMatch[i];
found = !!targetMap[cur];
// If found, `targetMap[cur]` will return true, otherwise it
// will return `undefined`...that's what the `!!` is for
}
return found;
};
DEMO: http://jsfiddle.net/5Lv9v/
The downside to this solution is that only numbers and strings (and booleans) can be used (correctly), because the values are (implicitly) converted to strings and set as the keys to the lookup map. This isn't exactly good/possible/easily done for non-literal values.
Using filter/indexOf:
function containsAny(source,target)
{
var result = source.filter(function(item){ return target.indexOf(item) > -1});
return (result.length > 0);
}
//results
var fruits = ["apple","banana","orange"];
console.log(containsAny(fruits,["apple","grape"]));
console.log(containsAny(fruits,["apple","banana","pineapple"]));
console.log(containsAny(fruits,["grape", "pineapple"]));
You could use lodash and do:
_.intersection(originalTarget, arrayToCheck).length > 0
Set intersection is done on both collections producing an array of identical elements.
const areCommonElements = (arr1, arr2) => {
const arr2Set = new Set(arr2);
return arr1.some(el => arr2Set.has(el));
};
Or you can even have a better performance if you first find out which of these two arrays is longer and making Set out for the longest array, while applying some method on the shortest one:
const areCommonElements = (arr1, arr2) => {
const [shortArr, longArr] = (arr1.length < arr2.length) ? [arr1, arr2] : [arr2, arr1];
const longArrSet = new Set(longArr);
return shortArr.some(el => longArrSet.has(el));
};
I wrote 3 solutions. Essentially they do the same. They return true as soon as they get true. I wrote the 3 solutions just for showing 3 different way to do things. Now, it depends what you like more. You can use performance.now() to check the performance of one solution or the other. In my solutions I'm also checking which array is the biggest and which one is the smallest to make the operations more efficient.
The 3rd solution may not be the cutest but is efficient. I decided to add it because in some coding interviews you are not allowed to use built-in methods.
Lastly, sure...we can come up with a solution with 2 NESTED for loops (the brute force way) but you want to avoid that because the time complexity is bad O(n^2).
Note:
instead of using .includes() like some other people did, you can use
.indexOf(). if you do just check if the value is bigger than 0. If
the value doesn't exist will give you -1. if it does exist, it will give you
greater than 0.
indexOf() vs includes()
Which one has better performance? indexOf() for a little bit, but includes is more readable in my opinion.
If I'm not mistaken .includes() and indexOf() use loops behind the scene, so you will be at O(n^2) when using them with .some().
USING loop
const compareArraysWithIncludes = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
return bigArray.includes(smallArray[i]);
}
return false;
};
USING .some()
const compareArraysWithSome = (arr1, arr2) => {
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
return smallArray.some(c => bigArray.includes(c));
};
USING MAPS Time complexity O(2n)=>O(n)
const compararArraysUsingObjs = (arr1, arr2) => {
const map = {};
const [smallArray, bigArray] =
arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
for (let i = 0; i < smallArray.length; i++) {
if (!map[smallArray[i]]) {
map[smallArray[i]] = true;
}
}
for (let i = 0; i < bigArray.length; i++) {
if (map[bigArray[i]]) {
return true;
}
}
return false;
};
Code in my:
stackblitz
I'm not an expert in performance nor BigO so if something that I said is wrong let me know.
You can use a nested Array.prototype.some call. This has the benefit that it will bail at the first match instead of other solutions that will run through the full nested loop.
eg.
var arr = [1, 2, 3];
var match = [2, 4];
var hasMatch = arr.some(a => match.some(m => a === m));
I found this short and sweet syntax to match all or some elements between two arrays. For example
// OR operation. find if any of array2 elements exists in array1. This will return as soon as there is a first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'b'];
console.log(array2.some(ele => array1.includes(ele)));
// prints TRUE
// AND operation. find if all of array2 elements exists in array1. This will return as soon as there is a no first match as some method breaks when function returns TRUE
let array1 = ['a', 'b', 'c', 'd', 'e'], array2 = ['a', 'x'];
console.log(!array2.some(ele => !array1.includes(ele)));
// prints FALSE
Hope that helps someone in future!
Just one more solution
var a1 = [1, 2, 3, 4, 5]
var a2 = [2, 4]
Check if a1 contain all element of a2
var result = a1.filter(e => a2.indexOf(e) !== -1).length === a2.length
console.log(result)
What about using a combination of some/findIndex and indexOf?
So something like this:
var array1 = ["apple","banana","orange"];
var array2 = ["grape", "pineapple"];
var found = array1.some(function(v) { return array2.indexOf(v) != -1; });
To make it more readable you could add this functionality to the Array object itself.
Array.prototype.indexOfAny = function (array) {
return this.findIndex(function(v) { return array.indexOf(v) != -1; });
}
Array.prototype.containsAny = function (array) {
return this.indexOfAny(array) != -1;
}
Note: If you'd want to do something with a predicate you could replace the inner indexOf with another findIndex and a predicate
Here is an interesting case I thought I should share.
Let's say that you have an array of objects and an array of selected filters.
let arr = [
{ id: 'x', tags: ['foo'] },
{ id: 'y', tags: ['foo', 'bar'] },
{ id: 'z', tags: ['baz'] }
];
const filters = ['foo'];
To apply the selected filters to this structure we can
if (filters.length > 0)
arr = arr.filter(obj =>
obj.tags.some(tag => filters.includes(tag))
);
// [
// { id: 'x', tags: ['foo'] },
// { id: 'y', tags: ['foo', 'bar'] }
// ]
Good perfomance solution:
We should transform one of arrays to object.
const contains = (arr1, mainObj) => arr1.some(el => el in mainObj);
const includes = (arr1, mainObj) => arr1.every(el => el in mainObj);
Usage:
const mainList = ["apple", "banana", "orange"];
// We make object from array, you can use your solution to make it
const main = Object.fromEntries(mainList.map(key => [key, true]));
contains(["apple","grape"], main) // => true
contains(["apple","banana","pineapple"], main) // => true
contains(["grape", "pineapple"], main) // => false
includes(["apple", "grape"], main) // => false
includes(["banana", "apple"], main) // => true
you can face with some disadvantage of checking by in operator (eg 'toString' in {} // => true), so you can change solution to obj[key] checker
Adding to Array Prototype
Disclaimer: Many would strongly advise against this. The only time it'd really be a problem was if a library added a prototype function with the same name (that behaved differently) or something like that.
Code:
Array.prototype.containsAny = function(arr) {
return this.some(
(v) => (arr.indexOf(v) >= 0)
)
}
Without using big arrow functions:
Array.prototype.containsAny = function(arr) {
return this.some(function (v) {
return arr.indexOf(v) >= 0
})
}
Usage
var a = ["a","b"]
console.log(a.containsAny(["b","z"])) // Outputs true
console.log(a.containsAny(["z"])) // Outputs false
My solution applies Array.prototype.some() and Array.prototype.includes() array helpers which do their job pretty efficient as well
ES6
const originalFruits = ["apple","banana","orange"];
const fruits1 = ["apple","banana","pineapple"];
const fruits2 = ["grape", "pineapple"];
const commonFruits = (myFruitsArr, otherFruitsArr) => {
return myFruitsArr.some(fruit => otherFruitsArr.includes(fruit))
}
console.log(commonFruits(originalFruits, fruits1)) //returns true;
console.log(commonFruits(originalFruits, fruits2)) //returns false;
When I looked at your answers, I could not find the answer I wanted.
I did something myself and I want to share this with you.
It will be true only if the words entered (array) are correct.
function contains(a,b) {
let counter = 0;
for(var i = 0; i < b.length; i++) {;
if(a.includes(b[i])) counter++;
}
if(counter === b.length) return true;
return false;
}
let main_array = ['foo','bar','baz'];
let sub_array_a = ['foo','foobar'];
let sub_array_b = ['foo','bar'];
console.log(contains(main_array, sub_array_a)); // returns false
console.log(contains(main_array,sub_array_b )); // returns true
Array .filter() with a nested call to .find() will return all elements in the first array that are members of the second array. Check the length of the returned array to determine if any of the second array were in the first array.
getCommonItems(firstArray, secondArray) {
return firstArray.filter((firstArrayItem) => {
return secondArray.find((secondArrayItem) => {
return firstArrayItem === secondArrayItem;
});
});
}
It can be done by simply iterating across the main array and check whether other array contains any of the target element or not.
Try this:
function Check(A) {
var myarr = ["apple", "banana", "orange"];
var i, j;
var totalmatches = 0;
for (i = 0; i < myarr.length; i++) {
for (j = 0; j < A.length; ++j) {
if (myarr[i] == A[j]) {
totalmatches++;
}
}
}
if (totalmatches > 0) {
return true;
} else {
return false;
}
}
var fruits1 = new Array("apple", "grape");
alert(Check(fruits1));
var fruits2 = new Array("apple", "banana", "pineapple");
alert(Check(fruits2));
var fruits3 = new Array("grape", "pineapple");
alert(Check(fruits3));
DEMO at JSFIDDLE
Not sure how efficient this might be in terms of performance, but this is what I use using array destructuring to keep everything nice and short:
const shareElements = (arr1, arr2) => {
const typeArr = [...arr1, ...arr2]
const typeSet = new Set(typeArr)
return typeArr.length > typeSet.size
}
Since sets cannot have duplicate elements while arrays can, combining both input arrays, converting it to a set, and comparing the set size and array length would tell you if they share any elements.
A short way of writing this:
const found = arr1.some(arr2.includes)
With underscorejs
var a1 = [1,2,3];
var a2 = [1,2];
_.every(a1, function(e){ return _.include(a2, e); } ); //=> false
_.every(a2, function(e){ return _.include(a1, e); } ); //=> true
Vanilla JS with partial matching & case insensitive
The problem with some previous approaches is that they require an exact match of every word. But, What if you want to provide results for partial matches?
function search(arrayToSearch, wordsToSearch) {
arrayToSearch.filter(v =>
wordsToSearch.every(w =>
v.toLowerCase().split(" ").
reduce((isIn, h) => isIn || String(h).indexOf(w) >= 0, false)
)
)
}
//Usage
var myArray = ["Attach tag", "Attaching tags", "Blah blah blah"];
var searchText = "Tag attach";
var searchArr = searchText.toLowerCase().split(" "); //["tag", "attach"]
var matches = search(myArray, searchArr);
//Will return
//["Attach tag", "Attaching tags"]
This is useful when you want to provide a search box where users type words and the results can have those words in any order, position and case.
Update #Paul Grimshaw answer, use includes insteed of indexOf for more readable
let found = arr1.some(r=> arr2.indexOf(r) >= 0)
let found = arr1.some(r=> arr2.includes(r))
I came up with a solution in node using underscore js like this:
var checkRole = _.intersection(['A','B'], ['A','B','C']);
if(!_.isEmpty(checkRole)) {
next();
}
You are looking for intersection between the two arrays. And you have two major intersection types: 'every' and 'some'. Let me give you good examples:
EVERY
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia'];
// Find 'every' brand intersection.
// Meaning all elements inside 'brands2' must be present in 'brands1':
let intersectionEvery = brands2.every( brand => brands1.includes(brand) );
if (intersectionEvery) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
If condition is not met (like if you put 'Mercedes' in brands2) then 'intersectionEvery' won't be satisfied - will be bool false.
If condition is met it will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common list.
Sandbox: https://jsfiddle.net/bqmg14t6/
SOME
let brands1 = ['Ford', 'Kia', 'VW', 'Audi'];
let brands2 = ['Audi', 'Kia', 'Mercedes', 'Land Rover'];
// Find 'some' brand intersection.
// Meaning some elements inside 'brands2' must be also present in 'brands1':
let intersectionSome = brands2.some( brand => brands1.includes(brand) );
if (intersectionSome) {
const differenceList = brands1.filter(brand => !brands2.includes(brand));
console.log('difference list:', differenceList);
const commonList = brands1.filter(brand => brands2.includes(brand));
console.log('common list:', commonList);
}
Here we are looking for some common brands, not necessarily all.
It will log ["Ford", "VW"] as difference and ["Kia", "Audi"] as common brands.
Sandbox: https://jsfiddle.net/zkq9j3Lh/
Personally, I would use the following function:
var arrayContains = function(array, toMatch) {
var arrayAsString = array.toString();
return (arrayAsString.indexOf(','+toMatch+',') >-1);
}
The "toString()" method will always use commas to separate the values. Will only really work with primitive types.
console.log("searching Array: "+finding_array);
console.log("searching in:"+reference_array);
var check_match_counter = 0;
for (var j = finding_array.length - 1; j >= 0; j--)
{
if(reference_array.indexOf(finding_array[j]) > 0)
{
check_match_counter = check_match_counter + 1;
}
}
var match = (check_match_counter > 0) ? true : false;
console.log("Final result:"+match);

Categories