javascript says two values are not equal when they are (using ===) - javascript

I want to use JavaScript to determine which class/display color a number of divs(called div1, div2...up through div21) are depending on the values in schedule_array. So if 2 is in schedule_array, I want div2 to be of class clicked and if 3 is not in schedule_array, I want div3 to be of class unclicked. The problem is that my === sign seems to be giving false no matter what for this code:
function setClasses()
{
alert("schedule array is "+schedule_array[3]);
for(var k = 1; k<22; k++)
{
var name = "div" + k;
if(contains(schedule_array, k))
{
document.getElementById(name).className = "clicked";
}
else
{
document.getElementById(name).className = "unclicked";
}
}
}
setClasses();
function contains(a, obj) {
//alert(a[3] + "for function contains");
//alert(a.length);
for (var i = 0; i < a.length; i++) {
document.write(a[i] + "=" + obj);
if (a[i] === obj) {
document.write("true,,,,,,,,");
return true;
}
else
{
document.write("false,,,,,,,,");
}
}
return false;
}
(stole this latter function from http://stackoverflow.com/questions/237104/array-containsobj-in-javascript)
I have no idea why, but the following code's == fails even when I am comparing the same integer to itself. For example with the code below I get output like:
21=21false,,,,,,
As you can see I've already checked to make sure schedule_array exists and has valid numbers. I have also checked to make sure both for loops are running. Finally, I confirmed that in js, even something like "5"==5 should give a true, so even if there is some weird typing going on, that shouldn't affect the outcome.
Question: what is up with this weirdness? What am I doing wrong?

This works for me.
function contains(a, obj) {
for (var i = 0; i < a.length; i++) {
if (a[i] == obj) {
return true;
}
}
return false;
}
alert(contains(['1', 2, 3, 4, 5], 1));
Are you sure that a is an array?
http://jsfiddle.net/kjruk00b/

You are using === which is a equality without conversion (strict equality). This means that, that although the numeric value is the same (equality) the strict equality operator is not coercing the String into a Integer to allow this comparison to happen. Switching to the non-strict equality operator == should solve your problem as it will convert the String into an Integer, allowing the comparison to work as you expected.
It may be worth your while looking at the Javascript truth tables for these 2 operators to get an idea for how they work.

Related

How to distinguish between Array's empty items and undefined?

I'm trying to implement a Linked List with Array's methods. Currently trying to implement indexOf and includes. I was looking into the following corner case:
var arr = [1,2,,4,5];
console.log(arr.indexOf(undefined));
console.log(arr.includes(undefined));
console.log(arr[2] === undefined);
Output:
-1
true
true
It looks like, for arr=[1,2,,4,5] it will actually keep undefined at arr[2]. Reading ECMA-262 and based on this page, indexOf uses "Strict Equality" (operator === ) and includes uses SameValueZero (Same as Object.is, except -0 is considered equal to +0). My functions are:
isStrictlyEqual(x,y) {
return x === y;
}
sameValue(x, y) {
return Object.is(x,y);
}
sameValueZero(x, y) {
return x === y || (Number.isNaN(x) && Number.isNaN(y));
}
The implementation of sameValueZero was taken from this topic.
My indexOf uses this isStrictlyEqual and my includes uses this sameValueZero. But, sameValueZero(undefined,undefined) returns true so My indexOf return index 2 for indexOf(undefined) while arr.indexOf(undefined) returns -1. Note that [1,2,undefined,4,5].indexOf(undefined) returns 2. So my only guess is that Array does not actually store this empty item as undefined.
I have a method that allows to fill a linked list from an existing array, like so:
_extend(iterable) {
for (var i = 0; i < iterable.length; ++i) {
this.push(iterable[i]);
}
In this case iterable[2] will return undefined so my DS will save undefined at index 2. Also tried to use forEach, but it actually skips the empty items.
I want my linked list to be similar to implementation of Array and follow ECMA specification. How my linked list should treat this corner case? Keeping undefined at that place, didn't work because of indexOf. I guess I need to distinguish between an empty item and undefined. How can I do so? I came across with this topic - does it mean I need to do two loops on the array? One regular for and one for in? Would I need to create a dummy node in that case? Does it make sense to do it for Linked list?
My linked list class:
class DoublyLinkedList {
constructor(array=null) {
this.head = null;
this.tail = null;
this.length = 0;
if (array !== null) {
this._extend(array);
}
}
}
Yes, you can (have to) add a dummy node and check for it in includes (and I guess also find and findIndex). Here's a POC:
const HOLE = Symbol()
class MyArray {
constructor() {
this.items = []
}
extend(a) {
for (let i = 0; i < a.length; i++)
this.items.push(
a.hasOwnProperty(i) ? a[i] : HOLE
)
}
indexOf(val) {
for (let i = 0; i < this.items.length; i++)
if (this.items[i] === val)
return i
return -1
}
includes(val) {
for (let i = 0; i < this.items.length; i++)
if (Object.is(this.items[i], val) || (val === undefined && this.items[i] === HOLE))
return true
return false
}
}
m = new MyArray()
m.extend([1, 2, 3, , 5])
console.log(m.indexOf(undefined))
console.log(m.includes(undefined))
m = new MyArray()
m.extend([1, 2, 3, undefined, 5])
console.log(m.indexOf(undefined))
console.log(m.includes(undefined))

Looking for a function that takes three arguments (x, y, z) and checks if the type of all three is a string

Don't know what to put before the for loop. Don't know if I need an if/else statement. Trying to have it display in the console if items in an array are strings. So I know I need consol.log
var stringOne = isString('rob','bob','carl')
function isString() {
//I dont know what to put before for loop
for(let i = 0; i < arguments.length; i++) {
// Dont know if i need an if/else statement
// Trying to have it display in the console if items in an array are strings
// So I know I need consol.log
}
}
every would be appropriate here, and doing I/O (like console.log) is better left outside of the function. The name of the function suggests that it should return a boolean (true/false):
function isString(...args) {
return args.every(s => typeof s === "string");
}
console.log(isString('rob','bob','carl'));
Because it seems like you're a beginner, I will expand upon the code that you currently have, although #trincot did the best solution.
In a for loop, you can return a value so the loop won't continue. Because you only need to check if any of them are false, may it be in position 0, 1 or 2 in the array, you can return "false" immediately.
If there are only strings, the loop will continue until it ends, and then return "true" at the end of the method.
So you don't need any code before the for loop, only an if statement that returns "false" if any of the items in the array isn't a string.
var stringOne = isString('rob','bob','carl')
var stringTwo = isString('rob','bob', 1)
function isString() {
for(let i = 0; i < arguments.length; i++) {
if (typeof arguments[i] != 'string') {
return false
}
}
return true
}
console.log({stringOne});
console.log({stringTwo});
Something like this in the loop ought to do it:
this_arg = arguments[i];
if (typeof this_arg === 'string') console.log("arg number " + i + " is a string");
It shows how to do it a bit here
You may find every useful here. It iterates over the array you've made from the arguments and checks to see if each element matches the condition. If they all match it returns true, otherwise false.
function isString() {
return Array.from(arguments).every(str => {
return typeof str === 'string';
});
}
console.log(isString('rob','bob','carl'));
console.log(isString(2,'bob','carl'));

Fast way to check if a javascript array is binary (contains only 0 and 1)

What is a quick way to determine if an array is only composed of 0's and 1's?
I'm vaguely familiar with a boolean solution but am not away how to implement it. In order to implement is you would have to assign values to the boolean
true = 0
and
false = 1
But how would you implement this if you are given an array such that
array = [1,1,1,1,0,0,0,0]
isArrayBool (){
}
Very very naive solution:
function isArrayBool(array) {
for (var i of array) {
if (i !== 0 && i !== 1) return false;
}
return true;
}
console.log(isArrayBool([1,0,0,0,1])); // true
console.log(isArrayBool([1])); // true
console.log(isArrayBool([2,3,0])); // false
So I threw a few functions together in jsperf to test. The fastest one I found so far is the one below (which is much faster than the for of version):
function isBoolFor(arr) {
for(var i=arr.length-1; i>=0; --i){
if(arr[i] !== 0 && arr[i] !== 1) return false
}
return true
}
Comparison is here
EDIT: I played around with another version that turned out to be quicker:
function isBoolFor(arr) {
for(var i=0; arr[i] === 0 || arr[i] === 1; i++){}
return i === arr.length
}
The key here is that because most of the array you are checking will consist of zeros and ones, you can avoid doing two boolean checks every iteration by using the || instead of the && negative check. It is only a subtle improvement, and could be argued to be no better than the one above in practicality.
UPDATE: So the difference between all the for and while variants is too subtle to declare an overall winner. So in that case I would go for readability. If you want binary use typed arrays!
FINAL UPDATE:
I was curious and wanted to find an even faster version, and it can be done if the array is known to be only numbers. If the array contains only numbers, then you can use a bitwise operator check for either of the values in question. For example:
function isBoolFor(arr) {
const test = ~0x01
for(var i=arr.length-1; i>=0; --i){
if(test & arr[i]){ return false }
}
return true
}
https://jsperf.com/bool-array-test-2/1
As we can see here, the fastest way to do this can be seen here... With a simple for loop, as suggested by user Jaromanda in a comment. This for loop blows other solutions out of the water in terms of speed.
var someArray = [1,0,1,1,1,1,0,0,1,0,1,0,0,1,0,1,0,1,1,1,1,0,1,1,0,1,0];
function simpleForLoop(array){
var numArgs = someArray.length;
for(var loop = 0; loop < numArgs; loop++){
var arg = someArray[loop];
if(arg !== 0 && arg !== 1){ return false; }
}
return true;
}
var isbool = simpleForLoop(someArray);

if statement evaluates incorrectly

function ipsBetween(start, end){
var count = 0;
for(var i = 0; i < 4; i++) {
if(start.split('.').slice(i, i + 1) != end.split('.').slice(i, i + 1)) {
count++;
}
}
return count;
}
I am trying to find all possible IP's between a range. The above code is just a starting. I was trying to split the IP in pieces and check if they are equal or not. While I was doing so, interesingly even if the values are equal it evaluates the if statement as true and increases the count. Here is my test case:
ipsBetween("10.0.0.0", "10.0.0.50")
This test case returns 4, whereas it should return 1. I don't know why this is happening. I implicity looked the values of start.split('.').slice(i, i + 1) and end.split('.').slice(i, i + 1) and the first three element is seem to be equal.
There's really no need to use .slice() here. (That's what's causing the problem: .slice() returns an array, and two different arrays will never be equal to each other.) Split the strings first and then just use array indexing:
var count = 0;
start = start.split("."); end = end.split(".");
for (var i = 0; i < start.length; ++i)
if (start[i] != end[i])
count++;
return count;
The reason is that operator != when comparing two list objects will return true if they're not the very same object: split returns a list of strings but slice(i, i+1) will return a list of length 1.
This means that you're comparing ["10"] with another ["10"] and they're two different list objects, so != will return true.
If you just compare the contents using x.slice(".")[i] instead of using slice then the result is what you were expecting.
PS: The operator != of Javascript is terrible and you should not use it and prefer instead !==. It would be the same in this case, but it's much nicer to work with because it doesn't do crazy things when the two types are different.
PS2: Seems a good idea to split the strings at each iteration?
You are comparing arrays not strings you want to compare the string values try this instead:
function ipsBetween(start, end){
var count = 0;
for(var i = 0; i < 4; i++) {
if(start.split('.').slice(i, i + 1)[0] != end.split('.').slice(i, i + 1)[0]) {
count++;
}
}
return count;
}
console.log(ipsBetween("10.0.0.0", "10.0.0.50"));
The problem is the array objects returned won't equal each other because they are not the same array ie. they are not located at the same spot in memory...

Faster code for checking repeated values in a JS array

var valueArray = ['ABC','DEF','GHI','ABC','JKL','MNO','DEF'];
var flag =false;
for(var i=0; i<valueArray.length; i++)
{
for(var j=0; j<valueArray.length; j++)
{
if(valueArray[j] == valueArray[i] && j != i)
{
flag = true;
break;
}
}
}
if(flag)
alert('same values found');
I am trying to validate one array by checking for duplicate values, i used above code, i don't think its a better way. is there any ways with jquery for this or some good js codes for it.
Not sure about jquery, but performance will be better with just one for loop:
for(var i = 0; i < valueArray.length; i++)
{
if (valueArray.indexOf(valueArray[i], i+1) != -1) {
flag = true;
break;
}
}
jsPerf test: http://jsperf.com/check-for-double-occurences
If you want a fast, compatible, "works everywhere" function that just checks for duplicates and doesn't require any library, consider:
function hasDups(arr) {
// Firstly copy array so don't affect original, then sort
var t = arr.slice().sort();
// If adjacent members have the same value, return true
for (var i=1, iLen=t.length; i<iLen; i++) {
if (t[i] === t[i-1]) return true;
}
return false;
}
console.log(hasDups(['abc','dvf','abc'])); // true
However you might want something a little more functional, e.g. that you can provide a compare function to so that, say, 'abc' == 'ABC' or '5' == 5.
Or if you want to use new features and avoid the copy and sort, consider:
function hasDups2(arr) {
var obj = {};
return arr.some(function(v){
if (obj.hasOwnProperty(v)) return true;
obj[v] = '';
});
}
The same strategy can be applied to the first as well and avoid ES5's some.
Note that both the above are only really suitable for comparing primitive values, though the first is better for that. If you want a reliable function to look for duplicate objects, that requires a bit more work.
Use jquery.unique() and compare the array size. If the size of the resultant array is not the same then return false.
Doc for jquery.unique()

Categories

Resources