JS Methods That Blew My Mind - Array.prototype.every() & Array.prototype.some()

·

3 min read

Okay, I've used forEach(), map(), filter() and my good old reliable friend for loop on arrays, but what the heck is every() and why/when would I need it?

Array.prototype.every()

The every() method tests whether all elements in the array pass the test implemented by the provided function. It returns a Boolean value.

I came across this method when trying to solve a coding problem where I was asked to write a function(str1, str2) that returns true if a portion of str1 characters can be rearranged to match str2, otherwise returns false.

My first solution was as below:

function scramble(str1, str2) {
    let targetObj = {}
    for (let i = 0; i < str2.length; i++) {
        let char = str2[i]
        targetObj[char] ? targetObj[char] += 1 : targetObj[char] = 1
    }

    for (let i = 0; i < str1.length; i++) {
        let char = str1[i]
        if (targetObj[char]) {
            targetObj[char] -= 1
            if (targetObj[char] == 0) {
                delete targetObj[char]
                if (Object.keys(targetObj) == 0) return true
            }
        }
    }

    return false
}

It passed all tests once, but later when I tried submitting it again, the tests timed out -- it didn't handle long strings well.

Inspired by others' solutions, I tried using Array.prototype.every() in my second try:

function scramble(str1, str2) {
    let str1Obj = {}
    for (let i = 0; i < str1.length; i++) {
        let char = str1[i]
        str1Obj[char] ? str1Obj[char] += 1 : str1Obj[char] = 1
    }

    return **str2.split('').every(char => --str1Obj[char] >= 0)**
}

This solution passed all tests, and took 10627ms.

It's interesting to note that when written the return in the way shown below, it took longer(11024ms):

return str2.split('').every(char => {
        str1Obj[char] -= 1
        return str1Obj[char] >= 0
    })

I also tried writing the first part of Solution 2 using Array.prototype.reduce(), and noticed that it was indeed slower than a for loop -- it took 11057ms to pass all tests, and when combined with the longer version of return above, it timed out.

let str1Obj = str1.split('').reduce((obj, char) => {
        obj[char] ? obj[char] += 1 : obj[char] = 1
        return obj
    }, {})

Final working code with comments:

function scramble(str1, str2) {
    // using reduce:
    /*
    let str1Obj = str1.split('').reduce((obj, char) => {
        obj[char] ? obj[char] += 1 : obj[char] = 1
        return obj
    }, {})
    */

    // using for loop
    let str1Obj = {}
    for (let i = 0; i < str1.length; i++) {
        let char = str1[i]
        str1Obj[char] ? str1Obj[char] += 1 : str1Obj[char] = 1
    }

    // 11024ms with for loop
    /*
    return str2.split('').every(char => {
        str1Obj[char] -= 1
        return str1Obj[char] >= 0
    })
    */

    // 10627ms with for loop, 11057ms with reduce
    return str2.split('').every(char => --str1Obj[char] >= 0)
}

#Array.prototype.some() The some() method tests whether at least one element in the array passes the test implemented by the provided function. It returns true if, in the array, it finds an element for which the provided function returns true; otherwise it returns false. It doesn't modify the array.

const array = [1, 2, 3, 4, 5]
// Tests if some elements in array are even numbers:
console.log(array.some(num => num % 2 === 0)) // true

Syntax:

some((element, index, array) => { /* … */ } ) // index and array are optional parameters