0

How to map items without undefined value in javascript with Array.prototype.map and without Array.prototype.filter()

Code:

var testArray = [
  {
    name: "toto",
    totoNumber: "1",
  },
  {
    name: "tata",
    totoNumber: "2",
  },
  {
    mame: "error",
  },
]

var listOfToto = testArray.map(x => x.totoNumber);
var listOfToto2 = testArray.map(x => x.totoNumber ? x.totoNumber : undefined);
var listOfToto3 = testArray.filter(x => x.totoNumber).map(x => x.totoNumber);

console.log(listOfToto);  
console.log(listOfToto2);  
console.log(listOfToto3);  

Values:

Array ["1", "2", undefined]
Array ["1", "2", undefined]
Array ["1", "2"]

I want to get the last array (["1", "2"]) without using Array.prototype.filter()
(maybe with something else than Array.prototype.map())

Other source:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
Why does javascript map function return undefined?
https://codewithhugo.com/avoiding-falsy-values-in-javascript-arrays/

4
  • 1
    "without using Array.prototype.filter()" - but... that's the whole purpose of array.filter(). I think you're concerned about the fact that you're using two loops (filter, then map). Don't be. Commented Jul 2, 2019 at 19:42
  • You could use reduce to build your new array and only include elements when they need to be there, but using map and filter will be much easier to read and to maintain Commented Jul 2, 2019 at 19:46
  • Also, filtering the other way is much easier and avoids code repetition: testArray.map(x => x.totoNumber).filter(e => e) (although if you can have zero as a value you might want to explicitly check for !== undefined) Commented Jul 2, 2019 at 19:48
  • The problem is that i am NOT supposed to have undefined values from the backend and i dont want to add .filter everywhere to be sure i'm not getting the same error as i had today. I was hoping for a .map2 Commented Jul 2, 2019 at 20:51

3 Answers 3

4

You can use Array.flatMap() and return an empty array [] if the value doesn't exist:

const testArray = [{"name":"toto","totoNumber":"1"},{"name":"tata","totoNumber":"2"},{"mame":"error"}]

const listOfToto2 = testArray.flatMap(x => x.totoNumber ? x.totoNumber : []);

console.log(listOfToto2);  

Sign up to request clarification or add additional context in comments.

3 Comments

This would be a solution, but its not the main use of flatMap. I would, in this case, keep the .filter and .map
Yep I would to. It's just an answer to a "can I..." question.
This helped me. In my case I was not working with an array, but I am working with the octokit pagination client so it's not an array but it streams each page through my mapping function. Under the covers it appears to be doing the equivalent of a flatMap. So returning an empty array was the "Aha" moment for me. I am a total javascript n00b, but wanted to mention that I think this streaming use case becomes a legitimate scenario where you want to map and filter at the same time via flatMap rather than streaming every page through a mapping that returns "undefined" before you can filter it later
0

You can use reduce.

let data = testArray.reduce((result, item) => item.totoNumber ? result.concat(item.totoNumber) : result, []);

// Or a slightly more efficient solution
// if you are worried about concat creating a new temporary array at each iteration

let data = testArray.reduce((result, item) => {
    if (item.totoNumber) {
        result.push(item.totoNumber);
    }
    return result;
}, []);

But why do you want to avoid filter? It makes the code much more readable (in my opinion), and unless you are dealing with a huge array or working in a very time-sensitive function, this will be a micro-optimization for which you should not sacrifice clarity.

This looks much cleaner in my opinion:

let data = testArray.map(item => item.totoNumber).filter(e => e);

2 Comments

The problem is that i am NOT supposed to have undefined values from the backend and i dont want to add .filter everywhere to be sure i'm not getting the same error as i had today. I was hoping to find something like .map2.
I mean you can make it. Array.prototype.map2 = function() { return this.map(...arguments).filter(e => e); } (you very likely shouldn't though, just find the source of your undefined values and make sure you handle it there)
0

Here are few options you can consider all which require one loop.

var arr = [ { name: "toto", totoNumber: "1", }, { name: "tata", totoNumber: "2", }, { mame: "error", }, ]

// via Array.forEach
let fe = []
arr.forEach(({totoNumber}) => totoNumber ? fe.push(totoNumber) : 0)

// via Array.reduce
let r = arr.reduce((acc,{totoNumber}) => (totoNumber ? acc.push(totoNumber) : 0, acc), [])

// via Array.map acting like Array.forEach 
let m = []
arr.map(({totoNumber}) => (totoNumber ? m.push(totoNumber) : 0, totoNumber))

console.log(fe)
console.log(r)
console.log(m)

In reality only the Array.reduce make sense and the usual way to handle your scenario would be via Array.filter and then Array.map but since you asked if you can do it with map only ... you could but map is supposed to return the exact same array length so it is not the best fit really.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.