-2

I try generate String from an array of JavaScript objects using the .map() method, with below code:

var array1 = [{
    "DepartmentId": 155,
    "DepartmentName": "Animation",
    "Selected": true
  },
  {
    "DepartmentId": 156,
    "DepartmentName": "Software Development",
    "Selected": false
  },
  {
    "DepartmentId": 161,
    "DepartmentName": "Testing",
    "Selected": false
  },
  {
    "DepartmentId": 160,
    "DepartmentName": "Account",
    "Selected": true
  }
];

// pass a function to map
const map1 = array1.map(function(e) {
  if (e.Selected == true) return e.DepartmentId;
}).join(',');

console.log(map1);

My expected output is: 155,160

but it gives me

Actual output is: 155,,,160

Ivar
  • 6,138
  • 12
  • 49
  • 61
Divyesh patel
  • 967
  • 1
  • 6
  • 21
  • 3
    `map` returns exactly the same amount of elements you give it, you maybe want to use `filter` then `map`. – Keith Oct 01 '19 at 09:39

5 Answers5

4

When the if is not fulfilled, undefined is returned from the callback, resulting in empty spots in the array when it gets joined. Use .filter first instead:

var array1 = [{
    "DepartmentId": 155,
    "DepartmentName": "Animation",
    "Selected": true
  },
  {
    "DepartmentId": 156,
    "DepartmentName": "Software Development",
    "Selected": false
  },
  {
    "DepartmentId": 161,
    "DepartmentName": "Testing",
    "Selected": false
  },
  {
    "DepartmentId": 160,
    "DepartmentName": "Account",
    "Selected": true
  }
];

// pass a function to map
const map1 = array1
  .filter(e => e.Selected)
  .map(e => e.DepartmentId)
  .join(',');

console.log(map1);

Or, to filter and map in a single iteration, use reduce instead:

var array1 = [{
    "DepartmentId": 155,
    "DepartmentName": "Animation",
    "Selected": true
  },
  {
    "DepartmentId": 156,
    "DepartmentName": "Software Development",
    "Selected": false
  },
  {
    "DepartmentId": 161,
    "DepartmentName": "Testing",
    "Selected": false
  },
  {
    "DepartmentId": 160,
    "DepartmentName": "Account",
    "Selected": true
  }
];

// pass a function to map
const map1 = array1
  .reduce((a, e) => {
    if (e.Selected) {
      a.push(e.DepartmentId);
    }
    return a;
  }, [])
  .join(',');

console.log(map1);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • You could also combine the `reduce` and `join` steps by calling `.reduce((a,e)=>{if(e.Selected){ if(a!==''){ a+=','; } a+=e.DepartmentId; } return a;}, '')` – CerebralFart Oct 01 '19 at 09:45
1

You need to filter first and then map the wanted property.

var array1 = [{ DepartmentId: 155, DepartmentName: "Animation", Selected: true }, { DepartmentId: 156, DepartmentName: "Software Development", Selected: false }, { DepartmentId: 161, DepartmentName: "Testing", Selected: false }, { DepartmentId: 160, DepartmentName: "Account", Selected: true }];

const map1 = array1
    .filter(({ Selected }) => Selected)
    .map(({ DepartmentId }) => DepartmentId)
    .join(',');

console.log(map1);

With a single function, you need to take flatMap.

var array1 = [{ DepartmentId: 155, DepartmentName: "Animation", Selected: true }, { DepartmentId: 156, DepartmentName: "Software Development", Selected: false }, { DepartmentId: 161, DepartmentName: "Testing", Selected: false }, { DepartmentId: 160, DepartmentName: "Account", Selected: true }];

const map1 = array1
    .flatMap(({ Selected, DepartmentId  }) => Selected ? DepartmentId : [])
    .join(',');

console.log(map1);
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
1

The normal way like pointed out, is first you would filter and then map.

Another option as pointed out in duplicate link is using reduce.

But I'd thought I add another option, you can map then filter too, and you can just do filter(Boolean).

var array1 = [{
    "DepartmentId": 155,
    "DepartmentName": "Animation",
    "Selected": true
  },
  {
    "DepartmentId": 156,
    "DepartmentName": "Software Development",
    "Selected": false
  },
  {
    "DepartmentId": 161,
    "DepartmentName": "Testing",
    "Selected": false
  },
  {
    "DepartmentId": 160,
    "DepartmentName": "Account",
    "Selected": true
  }
];

// pass a function to map
const map1 = array1.map(function(e) {
  if (e.Selected == true) return e.DepartmentId;
}).filter(Boolean).join(',');

console.log(map1);
Keith
  • 22,005
  • 2
  • 27
  • 44
  • this solutiomn does not reduce the compexity, because it filters at the last step and not in the first. just imagine, you have a million items and the result set contains only two, then you need to iterate the million items twice., instead of filtering with one mullion and just two for mapping. – Nina Scholz Oct 01 '19 at 10:06
  • @NinaScholz Yes, I understand how `filter` and `map` works.. :) Like pointed out I was just giving another option. If the OP had mentioned performance as a key concern I could understand your comment here. – Keith Oct 01 '19 at 10:12
  • performance is always a key, if not even mentioned. – Nina Scholz Oct 01 '19 at 10:13
  • @NinaScholz The key thing is that it works, and it's understandable, optimising is something that's normally done as a secondary concern. But anyway, lets take your 1 million example. Just done a benchmark on a million records, here are the results. `filter(Boolean) = 83.215ms` , `filter , map = 64.245ms`, and finally `flatMap = 175.615ms` This is on Chrome / Windows, of course different JS Engines might give different results here, but I think it makes the point. I know you have more experience with JS, but one thing I've learned over the years is try and avoid pre-optmizing. – Keith Oct 01 '19 at 10:32
0

One option is using reduce. This will loop thru each array elements and only include the the department ID of Selected array elements

var array1 = [{
    "DepartmentId": 155,
    "DepartmentName": "Animation",
    "Selected": true
  },
  {
    "DepartmentId": 156,
    "DepartmentName": "Software Development",
    "Selected": false
  },
  {
    "DepartmentId": 161,
    "DepartmentName": "Testing",
    "Selected": false
  },
  {
    "DepartmentId": 160,
    "DepartmentName": "Account",
    "Selected": true
  }
];

// pass a function to map
const map1 = array1.reduce(function(c, e) {
  if (e.Selected == true) return c.concat(e.DepartmentId);
  else return c;
}, []).join(',');

console.log(map1);

Shorter Version:

var array1 = [{"DepartmentId":155,"DepartmentName":"Animation","Selected":true},{"DepartmentId":156,"DepartmentName":"Software Development","Selected":false},{"DepartmentId":161,"DepartmentName":"Testing","Selected":false},{"DepartmentId":160,"DepartmentName":"Account","Selected":true}]

const map1 = array1.reduce((c, e) => e.Selected ? c.concat(e.DepartmentId) : c, []).join(',');

console.log(map1);
Eddie
  • 26,593
  • 6
  • 36
  • 58
0

Use map and filter together to achieve this

var array1 = [
        {
            "DepartmentId": 155,
            "DepartmentName": "Animation",
            "Selected":true
        },
        {
            "DepartmentId": 156,
            "DepartmentName": "Software Development",
            "Selected":false
        },
        {
            "DepartmentId": 161,
            "DepartmentName": "Testing",
            "Selected":false
        },
        {
            "DepartmentId": 160,
            "DepartmentName": "Account",
            "Selected":true
        }       
    ];

// pass a function to map
const map1 = array1.filter(function(e){
return e.Selected;
}).map(function(x){return x.DepartmentId}).join(',');

console.log(map1);
ellipsis
  • 12,049
  • 2
  • 17
  • 33