admin管理员组

文章数量:1129437

My code

 var arr = ['a','b',1];
 var results = arr.map(function(item){
                if(typeof item ==='string'){return item;}  
               });

This gives the following results

["a","b",undefined]

I don't want undefined in the results array. How can I do it?

My code

 var arr = ['a','b',1];
 var results = arr.map(function(item){
                if(typeof item ==='string'){return item;}  
               });

This gives the following results

["a","b",undefined]

I don't want undefined in the results array. How can I do it?

Share Improve this question edited Apr 2, 2021 at 10:32 Syscall 19.8k10 gold badges43 silver badges57 bronze badges asked Apr 16, 2013 at 12:26 Akshat Jiwan SharmaAkshat Jiwan Sharma 16k13 gold badges51 silver badges60 bronze badges 6
  • 5 Because you don't return anything unless it's a string. Therefore, the last item returns undefined. What do you expect to return if it's not a string? An empty string? – BenM Commented Apr 16, 2013 at 12:28
  • 3 @BenM if it is not a string I want nothing returned.Not even undefined. – Akshat Jiwan Sharma Commented Apr 16, 2013 at 12:34
  • 7 Looks like I was using the wrong method to do this.I will use filter as suggested. – Akshat Jiwan Sharma Commented Apr 16, 2013 at 12:35
  • 4 jQuery.map is actually smart enough to not include undefined and null values in the resulting array. – Donald T Commented May 1, 2013 at 14:13
  • 1 @DonaldTaylor In this case though it's more clear to use the filter method to what you want to do, filter out elements, not map one value to another. – Ikke Commented Sep 18, 2015 at 7:55
 |  Show 1 more comment

13 Answers 13

Reset to default 251

You aren't returning anything in the case that the item is not a string. In that case, the function returns undefined, what you are seeing in the result.

The map function is used to map one value to another, but it looks like you actually want to filter the array, which a map function is not suitable for.

What you actually want is a filter function. It takes a function that returns true or false based on whether you want the item in the resulting array or not.

var arr = ['a','b',1];
var results = arr.filter(function(item){
    return typeof item ==='string';  
});

Filter works for this specific case where the items are not modified. But in many cases when you use map you want to make some modification to the items passed.

if that is your intent, you can use reduce:

var arr = ['a','b',1];
var results = arr.reduce((results, item) => {
    if (typeof item === 'string') results.push(modify(item)) // modify is a fictitious function that would apply some change to the items in the array
    return results
}, [])

You can implement like a below logic. Suppose you want an array of values.

let test = [ {name:'test',lastname:'kumar',age:30},
             {name:'test',lastname:'kumar',age:30},
             {name:'test3',lastname:'kumar',age:47},
             {name:'test',lastname:'kumar',age:28},
             {name:'test4',lastname:'kumar',age:30},
             {name:'test',lastname:'kumar',age:29}]

let result1 = test.map(element => 
              { 
                 if (element.age === 30) 
                 {
                    return element.lastname;
                 }
              }).filter(notUndefined => notUndefined !== undefined);

output : ['kumar','kumar','kumar']

Since ES6 filter supports pointy arrow notation (like LINQ):

So it can be boiled down to following one-liner.

['a','b',1].filter(item => typeof item ==='string');

My solution would be to use filter after the map.

This should support every JS data type.

example:

const notUndefined = anyValue => typeof anyValue !== 'undefined'    
const noUndefinedList = someList
          .map(// mapping condition)
          .filter(notUndefined); // by doing this, 
                      //you can ensure what's returned is not undefined

If you have to use map to return custom output, you can still combine it with filter.

const arr = ['a','b',1]

const result = arr.map(element => {

  if(typeof element === 'string')
    return element + ' something'

}).filter(Boolean) // this will filter out null and undefined

console.log(result) // output: ['a something', 'b something']

You only return a value if the current element is a string. Perhaps assigning an empty string otherwise will suffice:

var arr = ['a','b',1];
var results = arr.map(function(item){
    return (typeof item ==='string') ? item : '';  
});

Of course, if you want to filter any non-string elements, you shouldn't use map(). Rather, you should look into using the filter() function.

var arr = ['a','b',1];
var results = arr.filter(function(item){
                if (typeof item ==='string') {return item;}  
               });

I run into this quite frequently where the type after filtering will still be string | number. So, to expand upon these solutions and include type safety you can use a user-defined type guard. https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates

const result = ['a','b',1].filter((item) => typeof item ==='string');
// result is typed as (string | number)[]

Better type safety using user-defined type guard

const result = ['a','b',1].filter((item): item is string => typeof item ==='string');
// result is now typed as string[]

The problem: the issue is arr.map() will do a full iteration of arr array length, i.e. map() method will loop as much as the length of arr is, no matter what condition you have inside it, so if you defined a condition inside it e.g. if(typeof item ==='string'){return item;} even if the condition is not happening, the map() will be forced to keep looping until finishing the looping of the whole arr so it will give you undefined for the rest of elements if the condition is not met.

The solutions:

Solution One: if you want to return the whole item in the array when the condition is met, you can use arr.filter() so the filter will return the whole item for the iteration e.g. if you have array of objects like bellow

const arr = [{name: "Name1", age: 25}, {name: "Name2", age: 30}, {name: "Name3", age: 25}]

and you want to return the whole objects when the condition is met like example below

const filteredItems = arr.filter((item)=>{if(item.age === 25){return true}})

console.log(filteredItems) //results: [{name: "Name1", age: 25}, {name: "Name3", age: 25}]

conclusion: filter() method returns an array of the whole items in it if the condition is met.

Solution Two: if you want to return only a specific data of the objects (or the whole object or any shape of data) in array i.e. if you want to return only the names in array without the ages, you can do this

const namesOnly = arr.map((item)=>{if(item.age === 25){return item.name}})

console.log(namesOnly) //results: ["Name1, udefined, "Name3"]

now to remove the undefined you just use filter() method on the results like below

const namesOnly = arr.map((item)=>{if(item.age === 25){return item.name}}).filter((item)=> !!item)

console.log(namesOnly) //results: ["Name1, "Name3"]

conclusion: map() method returns an array of specifically defined data in the return, and returns undefined if the condition is not met. so then we can use filter() method to remove the undefined.

Map is used when you want to produced new modified array from the original array. the simple answer may be for someone

      var arr = ['a','b',1];
      var results = arr.filter(function(item){
      // Modify your original array here
     return typeof item ==='string';  
     }).filter(a => a);

If you use it like this, your problem will be solved. Also, you will have a clean and short code

var _ = require('lodash'); //but first, npm i lodash --save
var arr = ['a','b',1];
var results = _.compact(
    _.map(arr, function(item){
        if(_.isString(item)){return item;}
    }
); //false, null, undefined ... etc will not be included

with ES6...

const _ = require('lodash'); //but first, npm i lodash --save
const arr = ['a','b',1];
const results = _.compact(
    _.map(arr, item => {
        if(_.isString(item)){return item;}
    }
);

You can filter records with .map easily using below example code

const datapoints = [
    {
        PL_STATUS: 'Packetloss',
        inner_outerx: 'INNER',
        KPI_PL: '97.9619'
    },
    {
        PL_STATUS: 'Packetloss',
        inner_outerx: 'OUTER',
        KPI_PL: '98.4621',
    },
    {
        PL_STATUS: 'Packetloss',
        inner_outerx: 'INNER',
        KPI_PL: '97.8770',
    },
    {
        PL_STATUS: 'Packetloss',
        inner_outerx: 'OUTER',
        KPI_PL: '97.5674',

    },
    {
        PL_STATUS: 'Packetloss',
        inner_outerx: 'INNER',
        KPI_PL: '98.7150',
    },
    {
        PL_STATUS: 'Packetloss',
        inner_outerx: 'OUTER',
        KPI_PL: '98.8969'
    }
];
const kpi_packetloss_inner: string[] = [];
datapoints.map((item: { PL_STATUS: string; inner_outerx: string; KPI_PL: string }) => {
    if (item.PL_STATUS === 'Packetloss' && item.inner_outerx === 'INNER') {
        kpi_packetloss_inner.push(item.KPI_PL);
    }
})
console.log(kpi_packetloss_inner);

本文标签: Why does JavaScript map function return undefinedStack Overflow