Home > Enterprise >  Why does X === (A || B || C) not match anything?
Why does X === (A || B || C) not match anything?

Time:05-01

I have an array that looks like this:

const subscriptions = [
    {
        "price": "20",
        "product": "apple",
        "quantity": 1,
    },
    {
        "price": "10",
        "product": "orange",
        "quantity": 1,
    },
    {
        "price": "10",
        "product": "orange",
        "quantity": 1,
    },
    {
        "price": "10",
        "product": "orange",
        "quantity": 1,
    },
]

And I want to pull out all the array elements with a "product" of either apple, banana, or pear.

So I am using filter() like so:

const currentPlans = subscriptions.filter(
  (subscription) =>
    subscription.product ===
    ('apple' || 'banana' || 'pear')
);

Since the array only has once instance of apple that should be what currentPlans contains.

But currentPlans is returning an empty array.

What am I doing wrong?

CodePudding user response:

The following line not going to work as you expect. The right-hand side evaluates one value first(apple) and then checks equality. It never checks for banana or pear.

subscription.product === ("apple" || "banana" || "pear")

You should use another array to keep matches. Try like below.

Using indexOf

const subscriptions = [ { price: "20", product: "apple", quantity: 1, }, { price: "10", product: "orange", quantity: 1, }, { price: "10", product: "orange", quantity: 1, }, { price: "10", product: "orange", quantity: 1, }, ];

const matches = ["apple", "banana", "pear"];

const currentPlans = subscriptions.filter(
  (subscription) => matches.indexOf(subscription.product) >= 0
);

console.log(currentPlans);

Using includes

 const subscriptions = [ { price: "20", product: "apple", quantity: 1, }, { price: "10", product: "orange", quantity: 1, }, { price: "10", product: "orange", quantity: 1, }, { price: "10", product: "orange", quantity: 1, }, ];

const matches = ["apple", "banana", "pear"];

const currentPlans = subscriptions.filter(
  (subscription) => matches.includes(subscription.product)
);

console.log(currentPlans);

CodePudding user response:

When you use conditional checks with respect to the equality check, as per the precedence level, the expression that is present on the right side of the equality check is evaluated first, so when you do 'apple'||'banana'||'pear', this statement alone evaluated and then checked against the expression on the left side.
So 'apple'||'banana'||'pear' would evaluate to be truthy with the value apple and when you check this value against subscription.product the filter array would effectively return an object where the value of the property product is apple.

const subscriptions = [
    {
        "price": "20",
        "product": "apple",
        "quantity": 1,
    },
    {
        "price": "10",
        "product": "orange",
        "quantity": 1,
    },
    {
        "price": "10",
        "product": "orange",
        "quantity": 1,
    },
    {
        "price": "10",
        "product": "orange",
        "quantity": 1,
    },
]
const currentPlans = subscriptions.filter(
  (subscription) =>
    subscription.product ===
    ('apple' || 'banana' || 'pear')
);

console.log(currentPlans)

Although this would work when filtering objects whose product's value is apple the logic is technically incorrect when you'd want to filter out values based on conditional checks. As mentioned above the conditional OR would always return the first value, i.e, apple, and check this value against each iterable value. In order to actually get this working with conditional checks, you'd have to individually check the value against every other value, like so:

const currentPlans = subscriptions.filter(
  (subscription) =>
    subscription.product === 'apple' || subscription.product === 'banana' || subscription.product === 'pear'
);

Or, an easier way to accomplish the same would be, by squashing all the values into an array and calling the includes method and passing the current iterable value as an argument.

const currentPlans = subscriptions.filter(
  (subscription) =>
    ['apple' || 'banana' || 'pear'].includes(subscription.product)
);

CodePudding user response:

Change to

const currentPlans = subscriptions.filter(
  (subscription) =>
    (subscription.product ===
    'apple' || 'banana' || 'pear')
);
  • Related