2

I am trying to figure out a way to do search while iterating an array. I came across find() method.

Here is the example given:

var inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];

function findCherries(fruit) { 
    return fruit.name === 'cherries';
}

console.log(inventory.find(findCherries)); 
// { name: 'cherries', quantity: 5 }

I need find a dynamic fruit name, but I can't figure out how to do it. In short, I am trying to do something like:

function findCherries(fruit, fruitName) { 
    return fruit.name === fruitName;
};

inventory.find(findCherries('cherries'))
//"true is not a function"

Is there a way to give find() an argument and find a match base on that argument? If not, what method allows me to search an array of object dynamically?

Iggy
  • 5,129
  • 12
  • 53
  • 87
  • Search for / read Eloquent JavaScript. The "problem" with the second form is the code eagerly evaluates the function call when it *should* pass a function-object; this can be solved easily with closures. – user2864740 May 19 '17 at 23:09
  • 1
    Ah, I see! "cherries" is not a function, that's why it didn't work. After reading the comments below, it makes sense to have a callback argument with the dynamic argument stubbed in it. Thanks! – Iggy May 19 '17 at 23:46

5 Answers5

5

With a closure (your function must return a function) like this:

function findFruitByName(name) {
    return function(fruit) {
        return fruit.name === name;
    }
}

inventory.find(findFruitByName('cherries'))
// {name: "cherries", quantity: 5}
Hugues M.
  • 19,846
  • 6
  • 37
  • 65
2

Try this

// find one
function findFruitByName(name, inventoy) {
  return inventory.find(function(item) {
    return item.name === name;
  });
}

// find all
function findFruitsByName(name, inventory) {
  return inventory.filter(function(item) {
    return item.name === name;
  });
}


let inventory = [
  {name: 'apples', quantity: 2},
  {name: 'bananas', quantity: 0},
  {name: 'cherries', quantity: 5},
  {name: 'cherries', quantity: 88}
];

console.log('One', findFruitByName('cherries', inventory));
console.log('All', findFruitsByName('cherries', inventory));
EyuelDK
  • 3,029
  • 2
  • 19
  • 27
2

While a closure is the standard-approach, you could also supply the thisArg to Array.prototype.find and write:

var inventory = [
    {name: 'apples', quantity: 2},
    {name: 'bananas', quantity: 0},
    {name: 'cherries', quantity: 5}
];

function findFruit(fruit) {
    return fruit.name == this;
};

console.log(inventory.find(findFruit, 'cherries'));

I don't recommend this approach here as it is a) less obvious and b) this is an Object and needs to be coerced into a primitive string either by non strict equality == or directly converting to String(this), but it can definitely come in handy.

Community
  • 1
  • 1
le_m
  • 19,302
  • 9
  • 64
  • 74
  • 2
    This is interesting approach compared to other answers. Thanks for sharing the trick! – Iggy May 19 '17 at 23:47
1

Is there a way to give find() an argument and find a match base on that argument?

Yes. Your first code sample already does that: the argument you are using is a function that looks for cherries.

The argument passed to .find() has to be a function that knows how to do the comparison you want. This comparison function can be defined anonymously right at the point where you need it:

let result = inventory.find(function(item) {
  return item.name === "cherries";
});

And you can use an arrow function to make the code significantly shorter:

let result = inventory.find(item => item.name === "cherries");

So if the value you are looking for is in some other variable:

let fruit = "cherries";
let result = inventory.find(item => item.name === fruit);
// OR
let result = inventory.find(function(item) {
  return item.name === fruit;
});

(Note that arrow functions aren't supported by IE, but neither is the `.find() method, so...)

nnnnnn
  • 147,572
  • 30
  • 200
  • 241
0

You could use thisArg of the find method as argument, like in the code bellow (I used filter, you can use find as well)

var myFind = function(el) {
  return (el.indexOf(this) !== -1); // check if 'el' string contains an 'arg' substring
};

console.log(["abc", "123", "xya", "xyz"]
            .filter(myFind, "a"));         // the argument is "a"
//output: ["abc", "xya"]
serge
  • 13,940
  • 35
  • 121
  • 205