21

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;
    }
});
8
  • just write return; Also, consider using Array.prototype.filter for this. Commented Jun 27, 2016 at 19:29
  • 2
    if i do that, it returns 'null' which I don't want Commented Jun 27, 2016 at 19:29
  • 3
    You probably want to use a method such as filter. map returns an element for every element you iterate over. Commented Jun 27, 2016 at 19:30
  • @Angular Change map to filter, return '' to false and return x.name to true Commented Jun 27, 2016 at 19:32
  • Or you could simply put return x.name === 'Everything' instead of the whole if...else Commented Jun 27, 2016 at 19:32

6 Answers 6

18

Use Array.prototype.filter:

Copy.names = rule.names.filter(function(x) {                                
    return x.name !=='Everything';
}).map(function (x) {
    return x.name;
});
Sign up to request clarification or add additional context in comments.

3 Comments

I did this, it's actually returning 'Everything' , which is wrong
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: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Shouldn't it be x.name !== 'Everything'?
18

Another solution with Array.filter():

names.map(
  (x) => x.name === 'Everything' && x.name
).filter(Boolean)

Comments

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.

3 Comments

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.
please dont ever import a heavy dependency for just one function...
@samthet I think the package gets reduced in the build package to include only the used functions
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);
   }
}

1 Comment

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.
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.

Comments

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
}, [])

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.