[jquery] Jquery how to find an Object by attribute in an Array

Given I have an array of "purpose" objects:

//array of purpose objects:
var purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

(for simplicity i am omitting other attributes)

Now I want to have a method that returns a specific one of the objects if a matching purpose name is found.

This is not working:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(){
      return this.purpose == purposeName;
    });
};

findPurpose("daily");

but it actually returns an empty array:

[]

I am using JQuery 1.5.2. I have also tried with $.each() but with no luck. Apparently, most JQuery methods are designed for usage with DOM elements (such as filter().

Any ideas on how to achieve this?

This question is related to jquery collections filter traversal

The answer is


The error was that you cannot use this in the grep, but you must use a reference to the element. This works:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(n, i){
      return n.purpose == purposeName;
    });
};

findPurpose("daily");

returns:

[Object { purpose="daily"}]

Use the Underscore.js findWhere function (http://underscorejs.org/#findWhere):

var purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

var daily = _.findWhere(purposeObjects, {purpose: 'daily'});

daily would equal:

{"purpose":"daily"}

Here's a fiddle: http://jsfiddle.net/spencerw/oqbgc21x/

To return more than one (if you had more in your array) you could use _.where(...)


I personally use a more generic function that works for any property of any array:

function lookup(array, prop, value) {
    for (var i = 0, len = array.length; i < len; i++)
        if (array[i] && array[i][prop] === value) return array[i];
}

You just call it like this:

lookup(purposeObjects, "purpose", "daily");

Javascript has a function just for that: Array.prototype.find. As example

function isBigEnough(element) {
  return element >= 15;
}

[12, 5, 8, 130, 44].find(isBigEnough); // 130

It not difficult to extends the callback to a function. However this is not compatible with IE (and partially with Edge). For a full list look at the Browser Compatibility


I have created a util service for my angular application. It have two function which use very often.

For example you have object.

First getting value from object recursively without throwing undefined error.

{prop: { nestedProp1: {nestedProp2: somevalue}}}; get nestedProp2 2 without undefined checks.

Second filter array on basis

[{prop: { nestedProp1: {nestedProp2: somevalue1}}}, {prop: { nestedProp1: {nestedProp2: somevalue2}}}];

Find object from array with nestedProp2=somevalue2

app.service('UtilService', function(httpService) {
this.mapStringKeyVal = function(map, field) {
    var lastIdentifiedVal = null;
    var parentVal = map;
    field.split('.').forEach(function(val){
        if(parentVal[val]){
            lastIdentifiedVal = parentVal[val]; 
            parentVal = parentVal[val]; 
        }
    });
    return lastIdentifiedVal;
}


this.arrayPropFilter = function(array, field,value) {
    var lastIdentifiedVal = null;
    var mapStringKeyVal = this.mapStringKeyVal;
    array.forEach(function(arrayItem){
        var valueFound = mapStringKeyVal(arrayItem,field);
        if(!lastIdentifiedVal  && valueFound && valueFound==value){
            lastIdentifiedVal = arrayItem;
        }
    });
    return lastIdentifiedVal;
}});

For solution for current question. inject UtilService and call,

UtilService.arrayPropFilter(purposeArray,'purpose','daily');

Or more advanced

UtilService.arrayPropFilter(purposeArray,'purpose.nestedProp1.nestedProp2','daily');

Best, Fastest way is

function arrayLookup(array, prop, val) {
    for (var i = 0, len = array.length; i < len; i++) {
        if (array[i].hasOwnProperty(prop) && array[i][prop] === val) {
            return array[i];
        }
    }
    return null;
}

you should pass reference on item in grep function:

function findPurpose(purposeName){
    return $.grep(purposeObjects, function(item){
      return item.purpose == purposeName;
    });
};

Example


No need for jQuery.

JavaScript arrays have a find method, so you can achieve that in one line:

array.find((o) => { return o[propertyName] === propertyValue }

Example


const purposeObjects = [
    {purpose: "daily"},
    {purpose: "weekly"},
    {purpose: "monthly"}
];

purposeObjects.find((o) => { return o["purpose"] === "weekly" }

// output -> {purpose: "weekly"}

If you need IE compatibility, import this polyfill in your code.


One more solution:

function firstOrNull(array, expr) {
  for (var i = 0; i < array.length; i++) {
    if (expr(array[i]))
      return array[i];
    }
  return null;
}

Using: firstOrNull([{ a: 1, b: 2 }, { a: 3, b: 3 }], function(item) { return item.a === 3; });

This function don't executes for each element from the array (it's valuable for large arrays)


copied from polyfill Array.prototype.find code of Array.find, and added the array as first parameter.

you can pass the search term as predicate function

_x000D_
_x000D_
// Example_x000D_
var listOfObjects = [{key: "1", value: "one"}, {key: "2", value: "two"}]_x000D_
var result = findInArray(listOfObjects, function(element) {_x000D_
  return element.key == "1";_x000D_
});_x000D_
console.log(result);_x000D_
_x000D_
// the function you want_x000D_
function findInArray(listOfObjects, predicate) {_x000D_
      if (listOfObjects == null) {_x000D_
        throw new TypeError('listOfObjects is null or not defined');_x000D_
      }_x000D_
_x000D_
      var o = Object(listOfObjects);_x000D_
_x000D_
      var len = o.length >>> 0;_x000D_
_x000D_
      if (typeof predicate !== 'function') {_x000D_
        throw new TypeError('predicate must be a function');_x000D_
      }_x000D_
_x000D_
      var thisArg = arguments[1];_x000D_
_x000D_
      var k = 0;_x000D_
_x000D_
      while (k < len) {_x000D_
        var kValue = o[k];_x000D_
        if (predicate.call(thisArg, kValue, k, o)) {_x000D_
          return kValue;_x000D_
        }_x000D_
        k++;_x000D_
      }_x000D_
_x000D_
      return undefined;_x000D_
}
_x000D_
_x000D_
_x000D_


If your array is actually a set of JQuery objects, what about simply using the .filter() method ?

purposeObjects.filter('[purpose="daily"]')

Examples related to jquery

How to make a variable accessible outside a function? Jquery assiging class to th in a table Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Getting all files in directory with ajax Bootstrap 4 multiselect dropdown Cross-Origin Read Blocking (CORB) bootstrap 4 file input doesn't show the file name Jquery AJAX: No 'Access-Control-Allow-Origin' header is present on the requested resource how to remove json object key and value.?

Examples related to collections

Kotlin's List missing "add", "remove", Map missing "put", etc? How to unset (remove) a collection element after fetching it? How can I get a List from some class properties with Java 8 Stream? Java 8 stream map to list of keys sorted by values How to convert String into Hashmap in java How can I turn a List of Lists into a List in Java 8? MongoDB Show all contents from all collections Get nth character of a string in Swift programming language Java 8 Distinct by property Is there a typescript List<> and/or Map<> class/library?

Examples related to filter

Monitoring the Full Disclosure mailinglist Pyspark: Filter dataframe based on multiple conditions How Spring Security Filter Chain works Copy filtered data to another sheet using VBA Filter object properties by key in ES6 How do I filter date range in DataTables? How do I filter an array with TypeScript in Angular 2? Filtering array of objects with lodash based on property value How to filter an array from all elements of another array How to specify "does not contain" in dplyr filter

Examples related to traversal

List directory tree structure in python? Jquery how to find an Object by attribute in an Array jquery find closest previous sibling with class jQuery find parent form Post order traversal of binary tree without recursion