19

Right now, if 'Everything' in the list is detected, the output becomes [""].
Expected output: []

Copy.names = rule.names.map(function(x) {                                
    if (x.name ==='Everything') {                                   
        return '';
    } else {
        return x.name;
    }
});
Tajmin
  • 353
  • 1
  • 7
  • 23
Angular
  • 603
  • 2
  • 9
  • 24
  • just write `return;` Also, consider using Array.prototype.filter for this. – theWanderer4865 Jun 27 '16 at 19:29
  • 2
    if i do that, it returns 'null' which I don't want – Angular Jun 27 '16 at 19:29
  • 3
    You probably want to use a method such as `filter`. `map` returns an element for every element you iterate over. – dyagmin Jun 27 '16 at 19:30
  • @Angular Change `map` to `filter`, `return ''` to `false` and `return x.name` to `true` – Bálint Jun 27 '16 at 19:32
  • Or you could simply put `return x.name === 'Everything'` instead of the whole if...else – Bálint Jun 27 '16 at 19:32
  • Map will always return SOMETHING, you will need to change it to filter or, using a regular for loop to get the desired behavior. – theWanderer4865 Jun 27 '16 at 19:34
  • guys, my backend expects an empty list [] if "everything" is selected. Otherwise, it expects a list of the other names ['apple', 'orange'] So what's the best way? – Angular Jun 27 '16 at 19:34
  • Possible duplicate of [Removing elements with Array.map in JavaScript](http://stackoverflow.com/questions/9289/removing-elements-with-array-map-in-javascript) – GingerPlusPlus Jun 27 '16 at 19:59

6 Answers6

17

Use Array.prototype.filter:

Copy.names = rule.names.filter(function(x) {                                
    return x.name !=='Everything';
}).map(function (x) {
    return x.name;
});
Dylon
  • 1,730
  • 15
  • 14
  • I did this, it's actually returning 'Everything' , which is wrong – Angular Jun 27 '16 at 19:38
  • If you are using the code in your original post, the problem is that Array.prototype.map applies a transformation to every element in your list. You must instead use some logic to remove or ignore elements you don't want. Array.prototype.map does not have the ability to ignore elements alone, so it must be combined with another function, like Array.prototype.filter: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter – Dylon Jun 27 '16 at 19:41
  • 1
    Shouldn't it be `x.name !== 'Everything'`? – GingerPlusPlus Jun 27 '16 at 19:45
17

Another solution with Array.filter():

names.map(
  (x) => x.name === 'Everything' && x.name
).filter(Boolean)
Yegor Belov
  • 321
  • 2
  • 9
2

If you can use Lodash (which I highly recommend), you can deal with it in elegant way by using _.flatMap:

Copy.names = _.flatMap(rule.names, function(x) {
    if (x.name ==='Everything') {                                   
        return [];
    } else {
        return [x.name];
    }
})

As you can see, it's similiar to map, except that you return array of items instead of item.

GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
  • 1
    One caveat to this approach is that you will create a temporary array for every element in rule.names. This isn't a big deal for just a few elements, but can become costly with large lists. – Dylon Jun 27 '16 at 19:37
  • please dont ever import a heavy dependency for just one function... – ddruganov Apr 06 '21 at 07:47
  • @samthet I think the package gets reduced in the build package to include only the used functions – Just Mohit Jun 10 '21 at 08:34
2

If you can use ES6, you can use generator for that:

Copy.names = Array.from(function* () {
    for (var x of rule.names) {
       if (x.name ==='Everything') {                                   
            // do nothing
       } else {
            yield x.name;
       }
    }
})

If not... you can always go for imperative way:

Copy.names = []

for (var x of rule.names) {
   if (x.name ==='Everything') {                                   
        // do nothing
   } else {
        Copy.names.push(x.name);
   }
}
GingerPlusPlus
  • 5,336
  • 1
  • 29
  • 52
  • I don't think that the first approach (Using Array.from with generator) works. I tried it in different ES6 enabled environments and it always returns an empty array. – Chris Aug 30 '17 at 06:45
0

An answer I wrote elsewhere covers this, but if you want to be able to accomplish the transform of Array.map() but also to change the output length, you would need to use Array.reduce().

Usually, though, it will make more sense to filter--preferably before you map, but if needed, then after.

Kyle Baker
  • 3,424
  • 2
  • 23
  • 33
0

For this you should use reduce instead of map, here an example:

Copy.names = rule.names.reduce(function (arr, x) {
  x.name !== 'Everything' && arr.push(x.name)
  return arr
}, [])
chemedev
  • 23
  • 6