更高效的数组搜索
More efficient array search
我想根据对象的唯一属性(即键)从对象数组中提取特定对象。
在下文中,我在 'arr' 中搜索一个元素,其中键为 8。
var myElement = arr.filter(function(element) {
return element.key === 8;
});
这行得通,但每次运行时,它都会遍历数组中的所有元素,即使在找到正确的元素之后也是如此。例如,如果它在索引 4 处找到 myElement,但数组中有 100 个元素,则该代码段的运行量比它需要的多 25 倍。
有没有更有效的方法,或者找到 myElement 时终止 filter() 的方法?
我觉得我错过了一些明显的东西......
for (var i=0; i<arr.length; i++) {
if (arr[i].key === 8) {
console.log('FOUND ITEM AT KEY '+8);
break;
}
}
您实际上想要一个 find
函数,它在第一次出现时 return 出现。如果您使用的是 ECMAScript 6 规范,则可以使用 Array.prototype.find
,或者您可以实现一个简单的 find
,例如:
function find8(arr) {
// type checks skipped for brevity
var i = 0,
j = arr.length;
for (; i < j; i++) {
if (arr[i].key === 8) {
return arr[i];
}
}
throw new Error('Not found');
}
如果你想要一个更通用的解决方案,它接受 谓词(即 functions
那个 return 一个布尔值),你可以编写一个更通用的函数喜欢:
function find(arr, predicate) {
// Again, type checks skipped for brevity
var i = 0,
j = arr.length;
for (; i < j; i++) {
// Note the condition is now a call to the predicate function
if (predicate(arr[i])) {
return arr[i];
}
}
throw new Error('Not found');
}
听起来像这样你会过得更好:
function findByKey(items, key) {
for (var index = 0; index < items.length; index++) {
var item = items[index];
if (item.key === key) {
return item;
}
}
return null;
}
请注意,如果您的列表已排序,您可以通过进行二进制搜索来改进它。虽然我个人建议散列(假设同一个密钥没有被使用两次)。类似于:
var array = [/* your data here... */];
var map = {};
//do this once; or once each time your array changes
for (var index = 0; index < array.length; index++) {
var item = array[index];
map[item.key] = item;
}
//now find things by doing this
var itemWithKey8 = map[8];
我会用一个简单的 for
循环来处理这个问题(使用一个函数进行通用重用):
function findObject(arr, cond)
for (i = 0; i < arr.length; i++) {
if (cond(arr[i]){
return arr[i];
}
}
}
// now call fincObject(myArray, function(element){element.key === 8})
或者,如果您知道自己将多次执行此操作,请创建一个映射,该映射应该快很多:
function makeMapping(arr, keyFunc){
var mapping = {};
for (var i = 0; i < arr.length; i++) {
mapping[keyFunc(arr[i])] = arr[i];
}
return mapping;
}
这个returns一个对象映射8到key.id === 8
的对象。您的 keyFunc
将是:
function keyFunc(element){
return element.key;
}
为什么要重新发明轮子?这里有很多类似的答案,所以我将分享一种不同的方法——到目前为止我最喜欢的方法。有一个名为 linq.js 的优秀库(包括独立版本和 jQuery 插件版本),它使搜索、过滤、排序等变得轻而易举。
var myElement = Enumerable.From(arr).FirstOrDefault(null, function(element) {
return element.key === 8;
});
在上面的例子中,第一个符合条件的元素被returned。如果没有找到,则为 null returned(第一个参数是 return 的默认值)。
我想根据对象的唯一属性(即键)从对象数组中提取特定对象。
在下文中,我在 'arr' 中搜索一个元素,其中键为 8。
var myElement = arr.filter(function(element) {
return element.key === 8;
});
这行得通,但每次运行时,它都会遍历数组中的所有元素,即使在找到正确的元素之后也是如此。例如,如果它在索引 4 处找到 myElement,但数组中有 100 个元素,则该代码段的运行量比它需要的多 25 倍。
有没有更有效的方法,或者找到 myElement 时终止 filter() 的方法?
我觉得我错过了一些明显的东西......
for (var i=0; i<arr.length; i++) {
if (arr[i].key === 8) {
console.log('FOUND ITEM AT KEY '+8);
break;
}
}
您实际上想要一个 find
函数,它在第一次出现时 return 出现。如果您使用的是 ECMAScript 6 规范,则可以使用 Array.prototype.find
,或者您可以实现一个简单的 find
,例如:
function find8(arr) {
// type checks skipped for brevity
var i = 0,
j = arr.length;
for (; i < j; i++) {
if (arr[i].key === 8) {
return arr[i];
}
}
throw new Error('Not found');
}
如果你想要一个更通用的解决方案,它接受 谓词(即 functions
那个 return 一个布尔值),你可以编写一个更通用的函数喜欢:
function find(arr, predicate) {
// Again, type checks skipped for brevity
var i = 0,
j = arr.length;
for (; i < j; i++) {
// Note the condition is now a call to the predicate function
if (predicate(arr[i])) {
return arr[i];
}
}
throw new Error('Not found');
}
听起来像这样你会过得更好:
function findByKey(items, key) {
for (var index = 0; index < items.length; index++) {
var item = items[index];
if (item.key === key) {
return item;
}
}
return null;
}
请注意,如果您的列表已排序,您可以通过进行二进制搜索来改进它。虽然我个人建议散列(假设同一个密钥没有被使用两次)。类似于:
var array = [/* your data here... */];
var map = {};
//do this once; or once each time your array changes
for (var index = 0; index < array.length; index++) {
var item = array[index];
map[item.key] = item;
}
//now find things by doing this
var itemWithKey8 = map[8];
我会用一个简单的 for
循环来处理这个问题(使用一个函数进行通用重用):
function findObject(arr, cond)
for (i = 0; i < arr.length; i++) {
if (cond(arr[i]){
return arr[i];
}
}
}
// now call fincObject(myArray, function(element){element.key === 8})
或者,如果您知道自己将多次执行此操作,请创建一个映射,该映射应该快很多:
function makeMapping(arr, keyFunc){
var mapping = {};
for (var i = 0; i < arr.length; i++) {
mapping[keyFunc(arr[i])] = arr[i];
}
return mapping;
}
这个returns一个对象映射8到key.id === 8
的对象。您的 keyFunc
将是:
function keyFunc(element){
return element.key;
}
为什么要重新发明轮子?这里有很多类似的答案,所以我将分享一种不同的方法——到目前为止我最喜欢的方法。有一个名为 linq.js 的优秀库(包括独立版本和 jQuery 插件版本),它使搜索、过滤、排序等变得轻而易举。
var myElement = Enumerable.From(arr).FirstOrDefault(null, function(element) {
return element.key === 8;
});
在上面的例子中,第一个符合条件的元素被returned。如果没有找到,则为 null returned(第一个参数是 return 的默认值)。