Jquery как найти объект по атрибуту в массиве

#jquery #collections #filter #traversal

#jquery #Коллекции #Фильтр #обход

Вопрос:

Учитывая, что у меня есть массив объектов «назначения»:

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

(для простоты я опускаю другие атрибуты)

Теперь я хочу иметь метод, который возвращает определенный из объектов, если найдено совпадающее имя назначения.

Это не работает:

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

findPurpose("daily");
  

но на самом деле это возвращает пустой массив:

 []
  

Я использую jQuery 1.5.2. Я также пробовал использовать $.each(), но безуспешно.
По-видимому, большинство методов jQuery предназначены для использования с элементами DOM (такими как filter() .

Есть идеи о том, как этого добиться?

Ответ №1:

Нет необходимости в jQuery.

В массивах JavaScript есть метод find, поэтому вы можете выполнить это в одной строке:

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

Пример

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

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

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

Если вам нужна совместимость с IE, импортируйте это полизаполнение в свой код.

Комментарии:

1. Я думаю, что if (purposeObjects[i].purposeName === purposeName) следует читать if (purposeObjects[i].purpose === purposeName)

2. это лучшее и оптимальная решение!! ты крутой приятель

Ответ №2:

вы должны передать ссылку на элемент в функции grep:

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

Пример

Комментарии:

1. точно! Это было именно то, что я в конечном итоге сделал.

2. Функция $.grep будет перебирать все элементы массива, даже если искомый объект уже был найден во время цикла. Это не оптимально. Ознакомьтесь с моим ответом.

3. Полностью согласен с Luca: $.grep() выполняет цикл по всему объекту, даже если вы возвращаете в условном! Для объектов меньшего размера это может быть неважно, но что, если объект действительно большой, как календарь до 2034 года? Я бы выбрал решение Луки Фаджиоли как лучший ответ

Ответ №3:

Лично я использую более универсальную функцию, которая работает для любого свойства любого массива:

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

Вы просто вызываете его следующим образом:

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

Комментарии:

1. Некоторые обстоятельства не позволяют этому работать в 100% случаев. У меня есть несколько методов, которые полагаются на этот метод — вызываемый каким-либо методом, он всегда работает, другими методами он никогда не работает. Я регистрирую все вызовы и не вижу видимой разницы между ‘works’ и ‘doesn’t. Этот вывод показывает, что третья итерация должна удовлетворять тесту и возвращать 3.true array[i][prop]: 19741 значение: 19741

Ответ №4:

Ошибка заключалась в том, что вы не можете использовать this в grep, но вы должны использовать ссылку на элемент. Это работает:

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

findPurpose("daily");
  

ВОЗВРАТ:

 [Object { purpose="daily"}]
  

Комментарии:

1. Функция $.grep будет перебирать все элементы массива, даже если искомый объект уже был найден во время цикла. Это не оптимально. Ознакомьтесь с моим ответом.

2. Полностью согласен с Luca: $.grep() выполняет цикл по всему объекту, даже если вы возвращаете в условном! Для объектов меньшего размера это может быть неважно, но что, если объект действительно большой, как календарь до 2034 года? Я бы выбрал решение Луки Фаджиоли как лучший ответ

Ответ №5:

Используйте Underscore.js Функция findWhere (http://underscorejs.org/#findWhere):

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

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

daily было бы равно:

 {"purpose":"daily"}
  

Вот пример: http://jsfiddle.net/spencerw/oqbgc21x /

Чтобы вернуть более одного (если у вас в массиве их было больше), вы могли бы использовать _.where(...)

Ответ №6:

Лучший и быстрый способ — это

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

Ответ №7:

Если ваш массив на самом деле представляет собой набор объектов jQuery, как насчет простого использования .метод filter() ?

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

Ответ №8:

Еще одно решение:

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

Используя: firstOrNull([{ a: 1, b: 2 }, { a: 3, b: 3 }], function(item) { return item.a === 3; });

Эта функция не выполняется для каждого элемента из массива (это полезно для больших массивов)

Ответ №9:

Я создал сервис util для своего приложения angular. У него есть две функции, которые используются очень часто.

Например, у вас есть object.

Сначала получаем значение из объекта рекурсивно, не выдавая неопределенную ошибку.

{prop: { nestedProp1: {nestedProp2: somevalue}}}; получаем nestedProp2 2 без неопределенных проверок.

Второй фильтр массива на основе

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

Найти объект из массива с помощью 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  amp;amp; valueFound amp;amp; valueFound==value){
            lastIdentifiedVal = arrayItem;
        }
    });
    return lastIdentifiedVal;
}});
  

Для решения текущего вопроса. внедрите UtilService и вызовите,

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

Или более продвинутый

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

Ответ №10:

В Javascript есть функция именно для этого: Array.prototype.find. В качестве примера

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

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

Нетрудно расширить обратный вызов функции. Однако это несовместимо с IE (и частично с Edge). Полный список смотрите на совместимость с браузерами

Ответ №11:

скопировано из polyfill Array.prototype.нашел код Array.find и добавил массив в качестве первого параметра.

вы можете передать поисковый запрос в качестве функции-предиката

 // Example
var listOfObjects = [{key: "1", value: "one"}, {key: "2", value: "two"}]
var result = findInArray(listOfObjects, function(element) {
  return element.key == "1";
});
console.log(result);

// the function you want
function findInArray(listOfObjects, predicate) {
      if (listOfObjects == null) {
        throw new TypeError('listOfObjects is null or not defined');
      }

      var o = Object(listOfObjects);

      var len = o.length >>> 0;

      if (typeof predicate !== 'function') {
        throw new TypeError('predicate must be a function');
      }

      var thisArg = arguments[1];

      var k = 0;

      while (k < len) {
        var kValue = o[k];
        if (predicate.call(thisArg, kValue, k, o)) {
          return kValue;
        }
        k  ;
      }

      return undefined;
}