28

I have this array:

var fruits = ['Apple', 'Banana', 'Orange', 'Celery'];

And I use Lodash's remove like so:

_.remove(fruits, function (fruit) {
  return fruit === 'Apple' || 'Banana' || 'Orange';
})

The result is ['Apple', 'Banana', 'Orange', 'Celery'], while I expected it to be ['Apple', 'Banana', 'Orange']. Why is this so?

5 Answers 5

57

Because when fruit is "Celery", you are testing:

"Celery" === 'Apple' || 'Banana' || 'Orange'

which evaluates to

false || true || true

which is true.

You can't use that syntax. Either do it the long way around:

_.remove(fruits, function (fruit) {
  return fruit === 'Apple' || fruit === 'Banana' || fruit === 'Orange'
});

or test for array membership:

_.remove(fruits, function (fruit) {
  return _.indexOf(['Apple', 'Banana', 'Orange'], fruit) !== -1
});

This is not limited to JavaScript, and is in fact a common mistake (e.g. this question)

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

1 Comment

Why not use _.includes instead of _.indexOf?
37

You can use the method _.pull from lodash 2.0 and up

var fruits = ['Apple', 'Banana', 'Orange', 'Celery'];

_.pull(fruits, 'Apple', 'Banana', 'Orange'); // ['Celery']

document.write(fruits);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.js"></script>

Comments

13

If you want to remove a set of items from another set, there are set operations intended specifically for that. Lodash has https://lodash.com/docs/4.17.2#difference which takes two array parameters A and B and will return another array which contains all of the elements of A which are not in B.

In your case, you could write

const fruits = ['Apple', 'Banana', 'Orange', 'Celery'];
const filteredFruits = _.difference(fruits, ['Apple', 'Banana', 'Orange']);

which will result in ['Celery'].

Comments

10

The problem isn't with Lo-Dash; your problem is with your conditional within your callback function. This:

return fruit === 'Apple' || 'Banana' || 'Orange';

Is not correct. You need to actually compare fruit with each string:

return fruit === 'Apple' || fruit === 'Banana' || fruit === 'Orange';

Or, you can use another Lo-Dash function to make it a little more compact:

_.remove(fruits, function (fruit) {
  return _.contains(['Apple', 'Banana', 'Orange'], fruit);
})

Note: In the latest versions of Lo-Dash the _.contains function is deprecated. Please use _.includes

Comments

2

Use an array of values that you'd like to compare against, and check for a returned index greater than -1. This indicates the value evaluated was found in the collection.

_.remove( fruits, function ( fruit ) {
  return _.indexOf( [ "Apple", "Banana", "Orange" ], fruit ) >= 0;
});

Alternatively you could use lo-dash's _.contains method to get a boolean response.

The problem with the approach you took was that you weren't comparing fruit against each one of those strings; instead, the only comparison taking place was fruit against "Apple", after that you were coercing strings all on their own.

Non-empty strings coerce to true (!!"Banana"), and as such are truthy. Therefore, the following condition will always short-circuit at "Banana" (unless fruit strictly equals "Apple"), returning true:

return fruit === "Apple" || 'Banana' || "Orange";

1 Comment

Note: Lodash no longer uses the function _.contains. It used to be an alias for _.includes, but is no longer as of 3.10.0. Use _.includes instead. github.com/mgonto/restangular/issues/1298

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.