基于多个键值对搜索对象数组的优化方法

时间:2016-10-21 03:46:05

标签: javascript algorithm search optimization data-structures

我写了一个通用扩展方法,它将返回一个匹配所有给定搜索条件(lookUpArray)的项目。这是Demo

/***************************Extension Method****************************/

    var utils = {};
            // Could create a utility function to do this
            utils.searchInArray = function (lookUpArray, caseSensitiveSearch) {
                if (!lookUpArray || lookUpArray.length <= 0)
                    return null;

                caseSensitiveSearch = caseSensitiveSearch || false;
                var self = this;
                var item = null;
                for (var index = 0; index < self.length; index++) {
                    item = self[index];
                    var exist = true;
                    for (var i = 0; i < lookUpArray.length; i++) {
                        if (item[lookUpArray[i].key] === lookUpArray[i].value) {
                            exist = exist * true;
                        } else { exist = exist * false; }
                    }
                    if (exist)
                        return item;
                };
                return exist ? item : null;
            };

            // or we could create a function on the Array prototype indirectly
            Array.prototype.excSearchObjArrayForKeyValue = utils.searchInArray;



/***************************Extension Method****************************/


        var inputObjectArray= [
            { emailType: 'primary', id: 1, username: 'saurabh', email: 'test@gmail.com', phone: '123' },
            { emailType: 'additional', id: 2, email: 'test2@gmail.com' },
            { emailType: 'additional', id: 2, email: 'test2@gmail.com', username:'spp' }
        ];

        //Below is the search criterion array. Extension method should return only that object which 
        //matches complete below lookUpArray
        var lookUpArray = [{ key: 'emailType', value: 'additional' }, { key: 'id', value: 2 }];

        var result = inputObjectArray.excSearchObjArrayForKeyValue(lookUpArray);
        console.log(result);

是否有可能在搜索之上优化(性能)?

4 个答案:

答案 0 :(得分:2)

这取决于您的使用案例。如果您将经常运行搜索功能(与修改数组的频率相比),并且如果您可以搜索有限数量的可能键,则可能会发现创建和维护类似索引的结构是值得的。现在,您的查找是O(m*n)操作,其中m是键的数量,n是数组中的项目数。有了适当的数据结构,查找可以成为O(m)操作。由于我猜测n可能是一个更大的数字,这可能会使搜索规模更有效率。

如果这样做没有意义,那么你至少应该缩短你的内循环。

            var self = this;
            for (var index = 0; index < self.length; index++) {
                var item = self[index];
                var matches = true;
                for (var i = 0; i < lookUpArray.length; i++) {
                    var lookUpItem = lookUpArray[i];
                    if (item[lookUpItem.key] !== lookUpItem.value) {
                        matches = false;
                        break;
                    }
                }
                if(matches) {
                    return item;
                }
            };
            return null;

或者,正如nnnnnn所说,你可以用标签更简洁地完成同样的事情:

            var self = this;
            outer:
            for (var index = 0; index < self.length; index++) {
                var item = self[index];
                for (var i = 0; i < lookUpArray.length; i++) {
                    var lookUpItem = lookUpArray[i];
                    if (item[lookUpItem.key] !== lookUpItem.value) {
                        continue outer;
                    }
                }
                return item;
            };
            return null;

如果您正在使用ES6,您甚至可以利用.find().every()功能。

            var self = this;
            return self.find(item => 
                lookUpArray.every(lookUpItem => 
                    item[lookUpItem.key] === lookUpItem.val));

我建议不要将此方法添加到Array原型中。我只是把它变成一种实用方法。

答案 1 :(得分:2)

您可以使用Array.prototype.filterArray.prototype.every等数组函数,而不是自己迭代项目:

var utils = {
  searchInArray: function(targetArray, lookupArray, caseSensitiveSearch) {
    return targetArray.filter(function(x) {
      return lookupArray.every(function(lookup) {
        if (x[lookup.key] === undefined)
          throw new Error('No ' + lookup.key + ' property in object ' + x);

        if (typeof x[lookup.key] !== typeof lookup.value)
          throw new Error('Type mismatch on property ' + lookup.key ' + in object ' + x);

        if (typeof lookup.value === 'string' && caseSensitiveSearch)
          return x[lookup.key].toLowerCase() === lookup.value.toLowerCase();
        else
          return x[lookup.key] === lookup.value;
      });
    });
  }
};

工作演示片段:

&#13;
&#13;
var utils = {
  searchInArray: function(targetArray, lookupArray, caseSensitiveSearch) {
    return targetArray.filter(function(x) {
      return lookupArray.every(function(lookup) {
        if (x[lookup.key] === undefined)
          throw new Error('No ' + lookup.key + ' property in object ' + x);

        if (typeof x[lookup.key] !== typeof lookup.value)
          throw new Error('Type mismatch on property ' + lookup.key ' + in object ' + x);

        if (typeof lookup.value === 'string' && caseSensitiveSearch)
          return x[lookup.key].toLowerCase() === lookup.value.toLowerCase();
        else
          return x[lookup.key] === lookup.value;
      });
    });
  }
};

var inputObjectArray = [
  { emailType: 'primary', id: 1, username: 'saurabh', email: 'test@gmail.com', phone: '123' }, 
  { emailType: 'additional', id: 2, email: 'test2@gmail.com' }, 
  { emailType: 'additional', id: 2, email: 'test2@gmail.com', username: 'spp' }
];

var lookUpArray = [{
  key: 'emailType',
  value: 'aDdItIoNaL'
}, {
  key: 'id',
  value: 2
}];

var result = utils.searchInArray(inputObjectArray, lookUpArray, true);
console.log(result);
&#13;
&#13;
&#13;

答案 2 :(得分:0)

您可以使用Arrays.find功能。

find()方法返回数组中的值(如果是数组中的元素) 满足提供的测试功能。否则返回undefined。

看看这个例子:

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 }

您也可以编写自定义逻辑,例如。找到素数:

function isPrime(element, index, array) {
  var start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}

console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5

如果有帮助,请标记正确。

答案 3 :(得分:0)

要获得第一个匹配的obj,您可以尝试这个

utils.searchInArray = function(lookUpArray, caseSensitiveSearch) {
    if (!lookUpArray || lookUpArray.length <= 0)
      return null;
    caseSensitiveSearch = caseSensitiveSearch || true;
    var self = this;
    return self.find(function(obj) {
      return lookUpArray.every(function(lookup) {
        if (typeof lookup.value === 'string' && caseSensitiveSearch)
          return obj[lookup.key].toLowerCase() === lookup.value.toLowerCase();
        else
          return obj[lookup.key] === lookup.value;
      });

    });
  };

获取所有匹配的对象

utils.searchInArray = function(lookUpArray, caseSensitiveSearch) {
    if (!lookUpArray || lookUpArray.length <= 0)
      return null;
    caseSensitiveSearch = caseSensitiveSearch || true;
    var self = this;
    return self.filter(function(obj) {
      return lookUpArray.every(function(lookup) {
        if (typeof lookup.value === 'string' && caseSensitiveSearch)
          return obj[lookup.key].toLowerCase() === lookup.value.toLowerCase();
        else
          return obj[lookup.key] === lookup.value;
      });

    });
  };