How do I check if elements exist in an array using .some()? - javascript

I am trying to see if a particular pair of numbers exist in an array. I know that .some() works effectively when it's a simple array, but I can't seem to get it to work in nested arrays.
Thank you in advance.
const array = [[1, 0], [2, 0], [3, 1], [4, 3], [5, 2]];
// checks whether an element exists
const exists = (i) => i == [3, 1] || [1, 3];
console.log(array.some(exists));
// expected output: true

You need to check every value because of different arrays, you have different object references, and you misused the logical OR operator. This does not include a comparison with another value.
const array = [[1, 0], [2, 0], [3, 1], [4, 3], [5, 2]];
const exists = ([a, b]) => a === 3 && b === 1 || a === 1 && b === 3;
console.log(array.some(exists));

Here is a general solution.
const array = [[1, 0], [2, 0], [3, 1], [4, 3], [5, 2]];
const expected = [[1, 3], [3, 1]];
const exists = (i) => expected.some((j) => {
return i.every((k, n) => j[n] === k);
});
console.log(array.some(exists));
This could be wrapped in a function to make it reusable.
const array = [[1, 0], [2, 0], [3, 1], [4, 3], [5, 2]];
const expected = [[1, 3], [3, 1]];
const containsAny = (array, expected) => {
return array.some((i) => expected.some((j) => {
return i.every((k, n) => j[n] === k);
}))
};
console.log(containsAny(array, expected));

You could make a custom function out of it which makes it reusable.
This is a simple example. By flattening the array you can check if values are the same.
Got my inspiration on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
const array = [[1, 0], [2, 0], [3, 1], [4, 3], [5, 2]];
const checkArrayFor = (needle, haystack) => {
const flattenNeedle = needle.join(':');
const flattenArray = haystack.map(item => item.join(':'));
return flattenArray.includes(flattenNeedle);
};
console.log("Check for [1, 0]", checkArrayFor([1, 0], array));
console.log("Check for [1, 1]", checkArrayFor([1, 1], array));

Related

How to group two-dimensional array by value at zero index

Let's say I have the following two-dimensional array:
const array = [[1, 1], [1, 2], [2, 1], [2, 2]];
What I want to do is to find all the values under first index which have common zero index value. So the result should be the following:
[[1, [1, 2]], [2, [1, 2]]]
Or maybe Map would look better:
[Map(1 => [1, 2]), Map(2 => [1, 2])]
How can I do that? With or without lodash. My solution looks a bit bloated and messy:
const array = [[1, 1], [1, 2], [2, 1], [2, 2]];
const grouppedCartItemsMap = new Map();
array.forEach((item) => {
const [locationId, contractId] = item;
if (!grouppedCartItemsMap.has(locationId)) {
grouppedCartItemsMap.set(locationId, [contractId]);
} else {
const existingItem = grouppedCartItemsMap.get(locationId);
if (!existingItem.includes(contractId)) {
grouppedCartItemsMap.set(locationId, [...existingItem, contractId]);
}
}
});
console.log(grouppedCartItemsMap);
If an object would work:
const array = [[1, 1], [1, 2], [2, 1], [2, 2]];
const grouped = {};
for (const [first, last] of array) {
grouped[first] ??= [];
grouped[first].push(last);
}
console.log(grouped);
This looks like a use case for reduce:
const array = [[1, 1], [1, 2], [2, 1], [2, 2]];
const grouppedCartItemsMap = array.reduce((acc, [locationId, contractId]) => {
if (!acc.has(locationId)) acc.set(locationId, [contractId]);
else acc.get(locationId).push(contractId);
return acc;
}, new Map());
console.log([...grouppedCartItemsMap.entries()]);

Deleting arrays of same elements in 2 dimensional array in Javascript

I am wondering how you would go about deleting arrays that contain the same elements in a 2 dimensional array.
For example:
let 2dArr = [ [1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1] ];
This array would delete the second and fourth elements, returning the 2d array:
returnedArr = [ [1, 2, 3],
[2, 4, 5],
[4, 3, 1] ];
How exactly could this be done, preserving the 2d array? I could only think to loop through elements, comparing elements via a sort, and deleting them as you go along, but this would result in an indexing error if an element is deleted.
1) You can easily achieve the result using reduce and Set as:
let twodArr = [
[1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1],
];
const set = new Set();
const result = twodArr.reduce((acc, curr) => {
const key = [...curr].sort((a, b) => a - b).join();
if (!set.has(key)) {
set.add(key);
acc.push(curr);
}
return acc;
}, []);
console.log(result);
2) You can also use filter as:
let twodArr = [
[1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1],
];
const set = new Set();
const result = twodArr.filter((curr) => {
const key = [...curr].sort((a, b) => a - b).join();
return !set.has(key) ? (set.add(key), true) : false;
});
console.log(result);
const seen = []
const res = array.filter((item) => {
let key = item.sort().join()
if(!seen.includes(key)){
seen.push(key)
return item
}
})
console.log(res)
You can use hash map
let arr = [ [1, 2, 3], [3, 2, 1],[2, 4, 5],[4, 5, 2],[4, 3, 1] ];
let obj = {}
let final = []
for(let i=0; i<arr.length; i++){
// create a key
let sorted = [...arr[i]].sort((a,b)=> a- b).join`,`
// check if this is not present in our hash map
// add value to final out and update hash map accordingly
if(!obj[sorted]){
obj[sorted] = true
final.push(arr[i])
}
}
console.log(final)
Using Array.prototype.filter() and a Set as thisArg
let arr = [ [1, 2, 3],
[3, 2, 1],
[2, 4, 5],
[4, 5, 2],
[4, 3, 1] ];
let res = arr.filter(function(e){
const sorted = [...e].sort((a,b) => a-b).join('|');
return this.has(sorted) ? false : this.add(sorted)
},new Set)
console.log(res)

.some() function not working with nested arrays?

For example, if I want to check whether arr1 (an array of 3 arrays) contains any element of arr2 (an array of 2 arrays), I use the .some() function, but it returns false.
let arr1 = [[1, 2], [2, 3], [3, 4]]
let arr2 = [[1, 2], [5, 2],]
if (arr1.some(x => arr2.includes(x))) {
alert('arr1 has arr2')
};
x does return the array [1, 2], but for some reason it doesn't pass the check for .some() in arr1.
.includes will return true if the passed item is === to one in the array, but separate objects are never === to each other in JS unless one was created from a reference from the other:
const arr = [1, 2];
console.log(arr === [1, 2]);
const arr2 = arr; // same reference
console.log(arr === arr2);
. I suppose one method would be to stringify the subarrays first:
let arr1 = [[1, 2], [2, 3], [3, 4]]
let arr2 = [[1, 2], [5, 2],]
if (arr1.some((subarr1) => {
const str1 = JSON.stringify(subarr1);
return arr2.some(subarr2 => JSON.stringify(subarr2) === str1);
})) {
console.log('arr1 has arr2')
}
I think includes function isn't working for arrays 2 dimension
Please change code like this
let arr1 = [[1, 2], [2, 3], [3, 4]]
let arr2 = [[1, 2], [5, 2],]
if (arr1.some(x => {
return arr2.some(item => item.toString() === x.toString())
})) {
alert('arr1 has arr2')
};
You can you _.isEqualof lodash to compare the Array.
let arr1 = [[1, 2], [2, 3], [3, 4]]
let arr2 = [[1, 2], [5, 2]]
if (arr1.some(x => {
return arr2.some(item => _.isEqual(item, x))
})) {
console.log('arr1 has arr2')
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>

Comparing arrays in arrays

I'm looking for a way to make comparisons between arrays in arrays.
let small = [[1, 3], [2, 2], [2, 3], [3, 0]];
let large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
For example, I would like to be able to find out how many of the arrays in small are found in large. Some function that, given the arrays above as arguments, would return 2, since [2, 2] and [3, 0] from small are found in large.
How would you go about doing that?
You can convert one of the arrays into a Set of hashes, and than filter the 2nd array using the set:
const small = [[1, 3], [2, 2], [2, 3], [3, 0]];
const large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
const containsCount = (arr1, arr2, hashFn) => {
const arr1Hash = new Set(arr1.map(hashFn));
return arr2.filter(s => arr1Hash.has(hashFn(s))).length;
}
const result = containsCount(small, large, ([a, b]) => `${a}-${b}`);
console.log(result);
You can try something like:
let small = [[1, 3], [2, 2], [2, 3], [3, 0]];
let large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
let z = zeta(small, large);
console.log(z);
function zeta(a, b) {
let join = m => m.join();
let x = a.map(join);
let y = b.map(join);
return x.reduce((n, m) => (y.indexOf(m)>0) ? ++n : n, 0);
}
I hope this helps!
Use every and some to compare the arrays with each other.
If you want to get an array containing the subarrays that match, use filter:
let result = small.filter(arr =>
large.some(otherArr =>
otherArr.length === arr.length && otherArr.every((item, i) => item === arr[i])
)
);
Which filters the subarray from small that some subarray from large has the same length and the same elements/items.
Demo:
let small = [[1, 3], [2, 2], [2, 3], [3, 0]];
let large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
let result = small.filter(arr =>
large.some(otherArr =>
otherArr.length === arr.length && otherArr.every((item, i) => item === arr[i])
)
);
console.log(result);
And if you want just a count, then use reduce instead of filter to count the mathched items (this makes use of the fact that the numeric value of true is 1 and that of false is 0):
let count = small.reduce((counter, arr) =>
counter + large.some(otherArr =>
otherArr.length === arr.length && otherArr.every((item, i) => item === arr[i])
)
, 0);
Demo:
let small = [[1, 3], [2, 2], [2, 3], [3, 0]];
let large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
let count = small.reduce((counter, arr) =>
counter + large.some(otherArr =>
otherArr.length === arr.length && otherArr.every((item, i) => item === arr[i])
)
, 0);
console.log(count);
Note: If the subarrays contain only numbers, the code could be simplified to use Array#toString instead of every and length comparaison:
let result = small.filter(arr => large.some(otherArr => "" + otherArr === "" + arr));
Which casts both arrays into strings and compares the two strings instead. This can be used with the reduce as well.
Create two nesting map() function oute for small and inner for large then use JSON.stringify()
let small = [[1, 3], [2, 2], [2, 3], [3, 0]];
let large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
var same=[];
small.map(function(element){
large.map(function(element2){
if(JSON.stringify(element)==JSON.stringify(element2)){
same.push(element);
}
});
});
console.log(same);
let small = [[1, 3], [2, 2], [2, 3], [3, 0]];
let large = [[1, 0], [1, 1], [2, 0], [2, 2], [2, 5], [3, 0], [3, 2]];
let largeArrayStringForm = large.map(item => item.toString())
let matchingItems = small.filter(item => largeArrayStringForm.includes(item.toString()))
console.log(`matchCount: ${matchingItems.length}`)

How to make _lodash.zip with less code

Definition:Creates an array of grouped elements, the first of which contains the first elements of the given arrays, the second of which contains the second elements of the given arrays, and so on.
Current Solution:
const zip = (...arr) => {
let maxLength = 0
let res = []
for (let el of arr) {
maxLength = Math.max(maxLength, el.length)
}
for (let j = 0; j < maxLength; j++) {
const foo = []
for (let n of arr) {
foo.push(n[j])
}
res.push(foo)
}
return res
}
Test Case:
test(('zip', () => {
expect(zip([1, 2], [4, 5], [9, 1])).toEqual([[1, 4, 9], [2, 5, 1]])
}
test('zip', () => {
expect(zip([1, 2, 3], [4, 5, 6])).toEqual([[1, 4], [2, 5], [3, 6]])
})
test('zip', () => {
expect(zip([1, 2], [], [3, 4, 5])).toEqual([
[1, undefined, 3],
[2, undefined, 4],
[undefined, undefined, 5],
])
})
I want to get a better way to achieve zip, current solution is ugly
See Destructuring Assignment and Array.prototype.map for more info.
// Proof.
const zip = (...args) => [...new Array(Math.max(...args.map(arr => arr.length)))].map((x, i) => args.map((y) => y[i]))
// Proof.
console.log(zip([1, 2], [4, 5], [9, 1])) // [[1, 4, 9], [2, 5, 1]]
console.log(zip([1, 2, 3], [4, 5, 6])) // [[1, 4], [2, 5], [3, 6]]
console.log(zip([1, 2], [], [3, 4, 5])) // [[1, undefined, 3], [2, undefined, 4], [undefined, undefined, 5]]

Categories