最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Finding the index of an object within an array efficiently - Stack Overflow

programmeradmin6浏览0评论

I am trying to find the index of an object within an array. I know there is a way to do this with underscore.js but I am trying to find an efficient way without underscore.js. Here is what I have :

var arrayOfObjs = [{
  "ob1": "test1"
}, {
  "ob2": "test1"
}, {
  "ob1": "test3"
}];

function FindIndex(key) {
  var rx = /\{.*?\}/;            // regex: finds string that starts with { and ends with }
  var arr = [];                  // creates new array
  var str = JSON.stringify(arrayOfObjs);          // turns array of objects into a string
  for (i = 0; i < arrayOfObjs.length; i++) {      // loops through array of objects
    arr.push(str.match(rx)[0]);                   // pushes matched string into new array
    str = str.replace(rx, '');                    // removes matched string from str
  }
  var Index = arr.indexOf(JSON.stringify(key));   // stringfy key and finds index of key in the new array
  alert(Index);
}

FindIndex({"ob2": "test1"});

JSFIDDLE

This works but I am afraid it isn't very efficient. Any alternatives?

I am trying to find the index of an object within an array. I know there is a way to do this with underscore.js but I am trying to find an efficient way without underscore.js. Here is what I have :

var arrayOfObjs = [{
  "ob1": "test1"
}, {
  "ob2": "test1"
}, {
  "ob1": "test3"
}];

function FindIndex(key) {
  var rx = /\{.*?\}/;            // regex: finds string that starts with { and ends with }
  var arr = [];                  // creates new array
  var str = JSON.stringify(arrayOfObjs);          // turns array of objects into a string
  for (i = 0; i < arrayOfObjs.length; i++) {      // loops through array of objects
    arr.push(str.match(rx)[0]);                   // pushes matched string into new array
    str = str.replace(rx, '');                    // removes matched string from str
  }
  var Index = arr.indexOf(JSON.stringify(key));   // stringfy key and finds index of key in the new array
  alert(Index);
}

FindIndex({"ob2": "test1"});

JSFIDDLE

This works but I am afraid it isn't very efficient. Any alternatives?

Share Improve this question asked Apr 29, 2016 at 20:24 AnthonyAnthony 1,5811 gold badge22 silver badges37 bronze badges 16
  • do you need it just once or more than once? – Nina Scholz Commented Apr 29, 2016 at 20:26
  • 3 You could, but it won't be any more efficient, it's still javascript – adeneo Commented Apr 29, 2016 at 20:33
  • 1 If comparing the stringified objects is enough, you could at least drop all the regex stuff, and just iterate -> jsfiddle.net/g30myfnh/1 – adeneo Commented Apr 29, 2016 at 20:36
  • 1 @Anthony That sounds like a better idea if you're able to do that. If you need to look up these objects and get their index (key) often, hash table would be a great solution. Hashtables are also surprisingly easy to write in JavaScript too, since everything in JavaScript is basically build off a hashtable already – Nick Zuber Commented Apr 29, 2016 at 20:37
  • 1 @Anthony Also, as a side note, when it comes to speed efficiency always try to avoid JSON.stringify(); that method is incredibly slow – Nick Zuber Commented Apr 29, 2016 at 20:38
 |  Show 11 more comments

6 Answers 6

Reset to default 7

Here's one way to do it, somewhat reliably and a little more efficiently, using some() and stopping as soon as the objects don't match etc.

var arrayOfObjs = [{
  "ob1": "test1"
}, {
  "ob2": "test1"
}, {
  "ob1": "test3"
}];

function FindIndex(key) {
    var index = -1;

    arrayOfObjs.some(function(item, i) {
    	var result = Object.keys(key).some(function(oKey) {
            return (oKey in item && item[oKey] === key[oKey]);
        });
        if (result) index = i;
        return result;
    });
    
    return index;
}

var index = FindIndex({"ob2": "test1"});

document.body.innerHTML = "'{\"ob2\": \"test1\"}' is at index : " + index;

A hash table with an example of access.

var arrayOfObjs = [{ "obj1": "test1" }, { "obj2": "test1" }, { "obj1": "test3" }],
    hash = {};

arrayOfObjs.forEach(function (a, i) {
    Object.keys(a).forEach(function (k) {
        hash[k] = hash[k] || {};
        hash[k][a[k]] = i;
    });
});

document.write('<pre>' + JSON.stringify(hash['obj2']['test1'], 0, 4) + '</pre>');
document.write('<pre>' + JSON.stringify(hash, 0, 4) + '</pre>');

One way of doing this would be to use every to see if each key in the "filter" has a matching, correct value in an object. every ensures that the loop stops as soon as it finds a mismatched or missing value.

function log(msg) {
  document.querySelector('pre').innerHTML += msg + '\n';
}

var arr = [
  {
    a: 1
  },
  {
    b: 2
  },
  {
    c: 3,
    d: 4
  },
  {
    a: 1 // Will never reach this since it finds the first occurrence
  }
];

function getIndex(filter) {
  var keys = Object.keys(filter);
  for (var i = 0, len = arr.length; i < len; i++) {
    var obj = arr[i];
    var match = keys.every(function(key) {
      return filter[key] === obj[key];
    });
    if (match) {
      return i;
    }
  }
  
  return -1;
}

log(getIndex({ a: 1 }));
log(getIndex({ b: 2 }));
log(getIndex({ c: 3 }));
log(getIndex({ c: 3, d: 4 }));
log(getIndex({ e: 5 })); // Doesn't exist, won't find it
<pre></pre>

For an alternative to your customly built approach, lodash's findIndex method does exactly this for you:

var arrayOfObjs = [{
  "ob1": "test1"
}, {
  "ob2": "test1"
}, {
  "ob1": "test3"
}];

_.findIndex(arrayOfObjs, {"ob2": "test1"}); // => 1

Since testing equality on two different objects will always return false you could first test keys and then values ,

using reduce :

var arrayOfObjs = [{
  "ob1": "test1"
}, {
  "ob2": "test1" , k2:2
}, {
  "ob1": "test3"
}];

function getI( obj, arr){
 const checkK= Object.keys(obj);
 return arr.reduce((ac,x,i) => {
  if ( checkK.every(z =>  x[z] && obj[z] === x[z]) )
    ac.push(i);
  return ac;
  },[])
}

document.write( 'result is :'+ getI({ob2:'test1', k2:2},arrayOfObjs))

findIndex won't work in old browsers, but was designed for this specific purpose.

var arrayOfObjs = [{
  "ob1": "test1"
}, {
  "ob2": "test1"
}, {
  "ob1": "test3"
}];

function FindIndex(key) {
  return arrayOfObjs.findIndex(
    obj => Object.keys(key).every(name => key[name] === obj[name])
  );
}

alert(FindIndex({"ob2": "test1"})); // 1

发布评论

评论列表(0)

  1. 暂无评论