Home > Software engineering >  .filter(_function) for arrays -- I'm not sure why the first version of my filter/function works
.filter(_function) for arrays -- I'm not sure why the first version of my filter/function works

Time:12-09

For this exercise I want to take an array with mixed data type, copy it to two new arrays, and then send each of these arrays through the .filter() function whose criteria I defined with two functions of my own. The first function I made should select all of the truthy data and return it one by one to a new, filtered array, which it does. However, my second function which should select all of the data that's falsy and return them to another array seems to only return an empty array.


let array_rawData = ['red', '', 0, 42, 'blue', 42, -0, 
null, undefined, NaN, 'hike!', 0n];

let _rawArrayData_toBeTruthy = array_rawData;
let _rawArrayData_toBeFalsy = array_rawData;

function truthy_Check (_rawData) {
    if ((_rawData !== '') 
        && (_rawData !== 0) 
        && (_rawData !== -0) 
        && (_rawData !== null) 
        && (_rawData !== undefined)
        && (_rawData !== 0n) 
        && (_rawData !== NaN)) {
        return _rawData;
    } 
}

function falsy_Check (_rawData) {
    if ((_rawData === '') 
        || (_rawData === 0) 
        || (_rawData === -0) 
        || (_rawData === null) 
        || (_rawData === undefined)
        || (_rawData === 0n) 
        || (_rawData === NaN)) {
        return _rawData;
    } 
}

let array_filteredForTruthy = _rawArrayData_toBeTruthy.filter(truthy_Check);
let array_filteredForFalsy = _rawArrayData_toBeFalsy.filter(falsy_Check);


console.log(array_filteredForTruthy);
console.log(array_filteredForFalsy);

If I console.log() the arrays after each step in the code, then it seems to be working fine, it's just that when the data is being returned and assigned to the final falsy array, it seems to not be returning it properly. What am I not understanding?

CodePudding user response:

For both truthy_Check and falsy_Check you should return true, if you want your value to be in filtered array. In your case you return the value itself. Truthy values are evaluated as true, and thus added to the return array. Falsy values are evaluated as false, and thus resulting array is empty. For example: falsy_Check evaluates 0. It passes one of conditions within if statement. And so 0 is returned. It is evaluated as false, and thus not added to the final array.

You can change your functions like this.

function truthy_Check (_rawData) {
    if ((_rawData !== '') 
        && (_rawData !== 0) 
        && (_rawData !== -0) 
        && (_rawData !== null) 
        && (_rawData !== undefined)
        && (_rawData !== 0n) 
        && (_rawData !== NaN)) {
        return true;
    } 
}

function falsy_Check (_rawData) {
    if ((_rawData === '') 
        || (_rawData === 0) 
        || (_rawData === -0) 
        || (_rawData === null) 
        || (_rawData === undefined)
        || (_rawData === 0n) 
        || (_rawData === NaN)) {
        return true;
    } 
}

But I do recommend evaluating truthy, falsy like this:

function truthy_Check (_rawData) {
    return _rawData;
}

function falsy_Check (_rawData) {
    return !_rawData
}

CodePudding user response:

As Mike correctly pointed out in the comments, your falsy_Check function should be returning true for elements that you want to keep during .filter.

However, I wanted to post an answer to mention a few additional things:

Checking "Truthyness"

"Truthyness" is most easily determined by coersing the value to a boolean. The simplest way to do that is to get the "not" of it by using the ! operator, and then "not" again to get back to the original value's boolean equivalent.

For example

console.log(!!1)
console.log(!!'hello')
console.log(!0)
console.log(!NaN)

So you can simplify your truthy/falsey check functions to (and BTW Javascript naming convention is to use camelCase for vars and functions)

function isTruthy(value) {
  return !!value
}
function isFalsey(value) {
  return !value
}

Arrays and Objects are passed like references

When you do

let array_rawData = ['red', '', 0, 42, 'blue', 42, -0, 
null, undefined, NaN, 'hike!', 0n];

let _rawArrayData_toBeTruthy = array_rawData;
let _rawArrayData_toBeFalsy = array_rawData;

all three vars are pointing to the same array in memory. The assignment operator doesn't make a copy. If you want to make a copy, there are plenty of ways, but the simplest (IMO) is to use the ES6 "splat" operator like let arrayCopy = [...originalArray]. But that doesn't matter in your case because...

The filter function creates a copy

array.filter(...) doesn't remove items from the array; it creates a new Array which only contains the items from the original array that matched the predicate function (which I have glossed over as ...)

And as mentioned above, the predicate function takes an item from the array and returns a Boolean, where true means "keep it" and false means "drop it".

Conclusion

const mixedArray = 
  ['red', '', 0, 42, 'blue', 42, -0, null, undefined, NaN, 'hike!', 0n]

const truthyItems = mixedArray.filter(x => !!x)
const falseyItems = mixedArray.filter(x => !x)

console.log('original:', mixedArray)
console.log('truthy:', truthyItems)
console.log('falsey:', falseyItems)

  • Related