3

I'm developing an annual permit calculator for work. I have to detect legal holidays. So I add all the legal holidays in my array. If date is equal to other array, it should return true. But the code says these two objects below are not equal. I couldn't figured out why.

var legalHolidays = [[1, 1, 2019], [23, 4, 2019], [1, 5, 2019], [19, 5, 2019], [3, 6, 2019]]

var otherArray = [1, 1, 2019]

if (legalHolidays[0] == otherArray) {console.log(true)}else{console.log(false)}

I expect the output of false to be true.

6 Answers6

2

But the code says these two objects below are not equal. I couldn't figured out why.

They are not equal because they are instances of different arrays that happen to have same values. In order to bypass this, one thing you could do is to convert the arrays into json strings and compare them instead:

var legalHolidays = [[1, 1, 2019], [23, 4, 2019], [1, 5, 2019], [19, 5, 2019], [3, 6, 2019]];

var otherArray = [1, 1, 2019];

// the date arrays are converted to JSON strings. This enables the arrays
// to be compared by their respective string representations, avoiding
// the problem of having to deal with the different references
const match = legalHolidays.find(holiday => JSON.stringify(holiday) === JSON.stringify(otherArray));

console.log(`Is found: ${!!match}`);

NOTE:

Converting the arrays to Json strings is not the only way of comparing them. Essentially, you need to reduce the problem to comparing primitives (which are compared by value, rather than by reference as it is done in case of objects).

Alex Lomia
  • 6,705
  • 12
  • 53
  • 87
0

Try this:

var x = legalHolidays.filter(function (elem) {
    return elem[0] == otherArray[0] && elem[1] == otherArray[1] && elem[2] == otherArray[2];
});

if(x.length > 0) {
    // otherArray is present in legalHolidays
}

Or more efficient,

var x = legalHolidays.find(function (elem) {
    return elem[0] == otherArray[0] && elem[1] == otherArray[1] && elem[2] == otherArray[2];
});

if(x) {
    // otherArray is present in legalHolidays
}

Or if the dates are in sorted order, try binary search (time complexity O(logn)):

function findDate(date, arrayOfDates) {
    var start = 0;
    var end = arrayOfDates.length-1;

    while(start < end) {
        var mid = parseInt(start + (end - start)/2);
        var elem = arrayOfDates[mid];
        if(elem[0] == otherArray[0] && elem[1] == otherArray[1] && elem[2] == otherArray[2]) {
            return mid;
        }

        if(elem[2] > date[2]) {
             start = mid + 1;
        }
        else if(elem[2] < date[2]) {
             end = mid - 1;
        }
        else if(elem[1] > date[1]) {
             start = mid + 1;
        }
        else if(elem[1] < date[1]) {
             end = mid - 1;
        }
        else if(elem[0] > date[0]) {
             start = mid + 1;
        }
        else {
             end = mid - 1;
        }
    }
}

console.log(findDate(otherArray, legalHolidays));

Little bit of more code, but efficient.

Furthermore, if all dates in legalHolidays are of the same year, you can skip the first 2 ifs in the while loop.

sanketd617
  • 809
  • 5
  • 16
0

This is because == and === only compare by reference. What you would need to do is to check every element of otherArray against all the elements in the arrays contained in legalHolidays?

To do so, you can use [].some, which

... tests whether at least one element in the array passes the test implemented by the provided function. It returns a Boolean value.

and a shallow equal function that compares two arrays elementwise. e.g. the one found in this answer

const legalHolidays = [
  [1, 1, 2019],
  [23, 4, 2019],
  [1, 5, 2019],
  [19, 5, 2019],
  [3, 6, 2019]
]

const otherArray = [1, 1, 2019]

const shallowEqual = (a, b) => {
  if (a === b) return true;
  if (a == null || b == null) return false;
  if (a.length != b.length) return false;

  // If you don't care about the order of the elements inside
  // the array, you should sort both arrays here.
  // Please note that calling sort on an array will modify that array.
  // you might want to clone your array first.

  for (var i = 0; i < a.length; ++i) {
    if (a[i] !== b[i]) return false;
  }
  return true;
}
const contains = (arrA, arrB) => arrA.some((arr) => {
  return shallowEqual(arr, arrB);
});

const contained = contains(legalHolidays, otherArray);
console.log(contained)

Please do not use the shallowEqual function provided in this answer, as it is not a complete implementation. It fails if you pass it something that is not array.

Moritz Roessler
  • 8,542
  • 26
  • 51
0

== is comparing the reference to the actual array instances, not the value of the array. You could create a function that converts to Date strings and compares them:

const otherArray = [1, 1, 2019];
var legalHolidays = [
  [1, 1, 2019],
  [23, 4, 2019],
  [1, 5, 2019],
  [19, 5, 2019],
  [3, 6, 2019]
]

function isSameDate(holidayItem, comparisonItem) {
  const [d1, m1, y1] = holidayItem;
  const [d2, m2, y2] = comparisonItem;

  if (new Date(y1, (m1 - 1), d1).toString() === new Date(y2, (m2 - 1), d2).toString()) {
    return true;
  }

  return false;
}

legalHolidays.forEach(holiday => {
  console.log(`Matches otherDate: ${isSameDate(holiday, otherArray)}`);
});
Tom O.
  • 5,730
  • 2
  • 21
  • 35
0

JavaScript compares arrays by reference when using equality operators, so if they are not the exact same object it will return false. You must either use JSON.stringify() to compare the string versions of the arrays:

if (JSON.stringify(legalHolidays[0]) == JSON.stringify(otherArray)) {
  console.log(true);
} else {
  console.log(false);
}

or manually compare the arrays at each index. In this example I use the every function:

const isLegal = legalHolidays[0].every((el, idx) => el === otherArray[idx]);
console.log(isLegal);
Zweih
  • 168
  • 10
0

You have an array of tuples. (A tuple is an array of a well-defined size in which each index has a specific meaning.) Each of your tuples has has three elements. This is why you can destrucuture your tuple via const [foo, bar, baz] = myArray;

Then you can find your existing array rather straighforward by comparing each of its values:

const hasDay = (haystack, needle) => {
  return haystack.some((holiday) => {
    const [day1, month1, year1] = holiday;
    const [day2, month2, year2] = needle;

    return day1 === day2 && month1 === month2 && year2 === year1;
  })
}

const legalHolidays = [[1, 1, 2019], [23, 4, 2019], [1, 5, 2019], [19, 5, 2019], [3, 6, 2019]]

console.log(
    hasDay(legalHolidays, [1, 1, 2019]), // will be true
    hasDay(legalHolidays, [1, 2, 2019])  // will be false
)
k0pernikus
  • 60,309
  • 67
  • 216
  • 347