Why can't I use Array#includes for a nested array? - javascript

Why does the following line return false in Javascript:
[[1,2,3], [1,2,4]].includes([1,2,3]);
What is the underlying logic behind that?

includes compares using SameValueZero equality algorithm. (As mentioned in developer.mozilla.org). When searching for objects (array is object as well), it will match only references to the same object.
Additionally, Javascript arrays are objects and you can't simply use the equality operator == to understand if the content of those objects is the same. The equality operator will only test if two object are actually exactly the same instance (e.g. myObjVariable==myObjVariable, works for null and undefined too).

Both [1,2,3] expressions create a new array object. Even though the contents are the same, the objects themselves are different.
See for example this:
const array1 = [1, 2, 3];
const array2 = [1, 2, 3];
console.log(array1 == array2); // false, different objects
const array = [1, 2, 3];
console.log(array == array); // true, same object

.includes check the equity for every value in the array. In JavaScript, two arrays with the same values are not equivalent. See this thread for more details: How to compare arrays in JavaScript?
You could do this to check if an array contains an array. I use Lodash for the equity comparison and the .some property to check if one element in the array returns true.
console.log(
[[1,2,3], [1,2,4]].some((array) => _.isEqual(array, [1,2,3]))
)
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.4/lodash.min.js"></script>

Because they are mutable. If you want to check for array, you need to check by variable.
var a = [1,2];
var b = a;
[a].includes(b);
When you check for [[1,2,]].includes([1,2,3]), it returns false, because they are treated as two different objects; i.e. [1,2] == [1,2] returns false.
However, for immutable objects, such as string and number, you can check directly, such as
["a", "b"].includes("a") //true
[1, 2].includes(1) //true
"a" == "a" // true

You can do it using only Array.some() (Array.prototype.some() more precisely) method like the followings
console.log([[1,2,3], [1,2,4]].some(e => e[0] === 1 && e[1] === 2 && e[2] === 3)); // would return 'true'
console.log([[1,2,3], [1,2,4]].some(e => e[0] === 1 && e[1] === 2 && e[2] === 4)); // would return 'true'
console.log([[1,2,3], [1,2,4]].some(e => e[0] === 1 && e[1] === 2 && e[2] === 5)); // would return 'false'

Related

Return the biggest number in the array (array contains a string)?

I dont understand why my code is not working, when I read it logically I feel that it should work, but what it does is return 3,4,2 as opposed to the highest number of the 3 (i.e. 4)
const array2 = ['a', 3, 4, 2] // should return 4
for(items of array2){
if(items > 0) {
console.log(Math.max(items));
}
What am I doing wrong? What have I misinterpreted? Please don't give me the answer, just tell me why my logic does'nt work
in for-loop, items is just one item actually. Each time, you print the current item. it is basically the same thing with this
const array2 = ['a', 3, 4, 2] // should return 4
for(items of array2){
if (items > 0) {
console.log(items);
}
}
you can do it with this only
const array2 = ['a', 3, 4, 2] // should return 4
console.log(Math.max(...array2.map(s => +s || Number.MIN_SAFE_INTEGER)));
check out: https://stackoverflow.com/a/44208485/16806649
if it was integer-only array, this would be enough:
const array2 = [3, 4, 2] // should return 4
console.log(Math.max(...array2));
You just need to filter the array.
Below example I am using filter() method of array and then just pass that filteredarray to Math.max() function.
isNan() function returns false for valid number.
Math.max(...filteredArr) is using spred operator to pass the values.
const arr = ['a', 3, 4, 2];
const filteredArr = arr.filter(val => {
if (!isNaN(val)) return val;
})
console.log(Math.max(...filteredArr));
I don't think you need the "For(items of arr)" instead just if the length of the array is greater than 0, then console.log(Math.max(...arr) should work.
See document ion below:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/max
It is returning 3,4,2 because you are taking array2, and iterating through with each individual element of the array. items is not the entire array, it is the individual element and that is why Math.max of an individual element is just getting the same value.
just you need fliter you're array then get max value, also in arrayFilters function use to removes everything only return numbers of this array
function arrayFilters(array){
const number = array.filter(element => typeof element === 'number')
return number;
}
function getMaxValue(number){
return Math.max.apply(null,number)
}
const arr = ['a',2,3,4];
console.log(getMaxValue(arrayFilters(arr)))

Javascript checking only the first item of an array

I have an array of arrays, i.e. [ [1,2], [1,3] ] and I want to check if is there any 1 as the first element of a subarray. It doesn't matter if it is a [1,2] or [1,3]. I'm interested only in the 1's existence. Sure I could use some loops to do this, but I wonder if is there an elegant "built-in" way to do this in js, something like:
arr.includes([1, _]) // returns true if is there any 1 as first element of an array
some is something you are looking for.
Code example:
const data = [[1, 3], [1, 5]]
const res = data.some( ([a, _]) => a === 1 ) // less elegant alternative:
// .some(e => e[0] === 1)
console.log(res)

Check if an array includes an array in javascript

The javascript includes function can be used to find if an element is present in an array. Take the following example:
var arr = ['hello', 2, 4, [1, 2]];
console.log( arr.includes('hello') );
console.log( arr.includes(2) );
console.log( arr.includes(3) );
console.log( arr.includes([1, 2]) );
Passing 'hello' or 2 to the function returns true, as both are present in the array arr.
Passing 3 to the function returns false because it is not present in the array.
However, why does arr.includes([1, 2]) return false as well, even though this is equal to the last element in the array? And if this method does not work, how else can I find whether my array includes the item [1, 2]?
.includes() method uses sameValueZero equality algorithm to determine whether an element is present in an array or not.
When the two values being compared are not numbers, sameValueZero algorithm uses SameValueNonNumber algorithm. This algorithm consists of 8 steps and the last step is relevant to your code , i.e. when comparison is made between two objects. This step is:
Return true if x and y are the same Object value. Otherwise, return false.
So in case of objects, SameValueZero algorithm returns true only if the two objects are same.
In your code, since the array [1, 2] inside arr array is identically different to [1, 2] that you passed to .includes() method, .includes() method can't find the array inside arr and as a result returns false.
The Array#includes checks by shallow comparison, so in your case the string and numbers are primitives there is only ever a single instance of them so you get true from Array#includes.
But when you check for array, you are passing a new array instance which is not the same instance in the array you are checking so shallow comparison fails.
To check for an array is included in another array first check if it is an array then do a deep comparison between the arrays.
Note that below snippet only works for an array of primitives:
var arr = ['hello', 2, 4, [1, 2]];
const includesArray = (data, arr) => {
return data.some(e => Array.isArray(e) && e.every((o, i) => Object.is(arr[i], o)));
}
console.log(includesArray(arr, [1, 2]));
But if you keep the reference to the array [1, 2] and search with the reference the Array#includes works as in this case the shallow comparison works perfectly (obeying same value zero algorithm):
const child = [1, 2];
const arr = ['hello', 2, 4, child];
console.log(arr.includes(child));
If you don't mind using lodash, this algorithm is accurate - unlike the accepted answer.
import _ from 'lodash';
export const includesArray = (haystack, needle) => {
for (let arr of haystack)
if (_.isEqual(arr, needle)) {
return true
}
return false
}

In a Javascript ternary operator, can you loop through an array? [duplicate]

This question already has answers here:
How do I check if an array includes a value in JavaScript?
(60 answers)
Closed 3 years ago.
I have a ternary operator which sees if values in an array are the same as my targeted value. Is there an easy way to do what I'm trying to do to save me a lot of time and hard coding in array indexes. Is there a way to not use a lot of or operator?
I essentially have a long list of array indexes to compare against like this:
(price[0] === this.props.result.cost ||
price[1] === this.props.result.cost ||
price[2] === this.props.result.cost ||
price[3] === this.props.result.cost ||
price[4] === this.props.result.cost )
? this
: that
I feel like there is something basic that I'm missing or some other way completely to make this an easier task to do.
If you are checking for primitives (integers, strings) in your array, then Array.prototype.includes is the simplest choice. It also successfully determines the presence of NaN in the array:
const price = [1, 2, 'str', 3, NaN, {'foo': 'bar'}];
//true
console.log(price.includes(3));
//true
console.log(price.includes('str'));
//true
console.log(price.includes(NaN));
//false
console.log(price.includes({'foo': 'bar'}));
In the above snippet all except the check for the object returns true, in case of object the reference is not the same so it returns false.
You can use Array.prototype.some for the test checking the presence of a particular attribute of an object:
const price = [1, 2, 'str', 3, 4, NaN, {'foo':'bar'}, 5];
let cost = 5;
//true
console.log(price.some((obj) => obj === cost));
//for checking if there is an object in the arrray with the attribute value 'foo' which has the value 'bar'
cost = 'bar';
//true
console.log(price.some((obj) => obj.foo == cost));
Or a ES6 Set can be used for constant time lookup, if the input array is big enough:
const price = [1, 2, 3, 4, 5];
const cost = 5;
console.log(new Set(price).has(cost));

Remove array from inside array based on index in JS

I have an array which looks like:-
[[0,1], [0,2], [0,3], [1,1], [1,2]...]
I am looking to remove one of the arrays from this array based on the indexOf() but I keep getting a value of -1, which removes the last item from the array when I try the following code:-
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
console.log('Removed value', array.splice(array.indexOf([0,3]), 1));
console.log('Result', array);
would somebody be able to point me in the right direction to help solve this issue I am having?
Thank you in advance.
You can't use indexOf because when you declare [0,3] in array.splice(array.indexOf([0,3]), 1)) you're creating a new array and this new object is not inside your array (but rather another array that has the same values).
You can use findIndex instead as follows (example):
array.findIndex(x => x[0] === 0 && x[1] === 3)
this will return 2 - now you can use it to delete:
array.splice(2, 1)
If it is OK to remove every occurrence of [0,3], then consider Array.filter combined with array destructuring of the lambda arguments. It offers a slightly leaner syntax than the other solutions.
const input = [
[0,1],
[0,2],
[0,3],
[1,1],
[1,2]
];
const result = input.filter(([x,y]) => !(x==0 && y==3));
console.log('Result=', result);
To explain why your solution will not work:
Comparison operators only work for values not passed by a reference. When dealing references, comparison operators always return false, unless the two references point to the same object. (See this on MDN)
An example:
a = [0,1]
b = a
b === a //true. a and b point to the same array.
a === [0,1] //false. a points to a different array than [0,1]
b[0] = 2
a[0] //2 - b points to the same array as a
To give you a solution (borrows from here)
//Function to compare the values inside the arrays, and determine if they are equal.
//Note: does not recurse.
function arraysEqual(arr1, arr2) {
if(arr1.length !== arr2.length)
return false;
for(var i = arr1.length; i--;) {
if(arr1[i] !== arr2[i])
return false;
}
return true;
}
array = [[0,1], [0,2], [0,3], [1,1], [1,2]];
//Find the index where x has the same values as [0,3]
array.findIndex(x => arraysEqual(x, [0,3])) //2

Categories

Resources