有没有一种快速的方法从Javascript中的对象数组中选择项目?

时间:2014-11-23 12:21:24

标签: javascript arrays node.js javascript-objects

我有一个数组:

[
    {
        key: 'some key',
        value: 'some value'
    }, {
        ...
    }, ...
]

有没有简单的方法来获取此数组的某个元素而不迭代它并将每个实际键与所需的键进行比较?

我目前有一个功能

var select = function(what, from) {
    for (var i in from) {
        if (from[i].key == what) {
            return from[i];
        }
    }
    return null;
};

我相信有更好的方法来处理它。

8 个答案:

答案 0 :(得分:2)

简短的回答是。有很多选项可以让你的代码更清晰 - 就像上面所有的一样 - 但是你仍然需要逐个迭代它们。

你可以做两件事来改善它:

转换为地图

如果您要进行多次或两次搜索,请将其转换为键的映射,因此至少每次后续查找都是O(1)而不是O(n)。一些答案表明 - 我在自己的代码中使用了很多 - 但这里是一个基本版本(有一个简写非下划线/ lodash):

var i, hash = {};
for (i = 0; i < arr.length; i++) {
  hash[arr[i].key] = arr[i].value;
}

然后对于所有将来的查找都很简单:

var value = hash[key];

搜索算法

如果由于某种原因需要保留为数组,并且您对该数组的值有所了解,则可以使用各种搜索算法。逐个循环它们对于均匀分布是有利的,但仍然是O(n),平均每次需要循环一半的数组(n / 2)。

但搜索算法超出了这个帖子......

答案 1 :(得分:1)

你很亲密。在这种特殊情况下,这将是最快的形式:

var select = function(key, expected, from) {
    var i;
    for (i = 0; i < from.length; i += 1) {
        if (from[i][key] === expected) {
            return from[i];
        }
    }
    return null;
};

select('thing', 'foo', [{thing: 'foo'}]);
// => {thing: 'foo'}

但你需要最高速度吗?或者更优雅,通用的解决方案适合您?如果是这样,请使用谓词:

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

// Find, in an array, an item which passes the following truth test.
find([{thing: 'foo'}], function (item) {
    return item.thing === 'foo';
});
// => {thing: 'foo'}

如果您不喜欢编写像这样的样板实用程序代码,我建议利用像lodash这样的库。 It has a find method already它比我们想出的任何东西都更快,更强大。

答案 2 :(得分:1)

如果你使用的是现代浏览器,这应该是神奇的:

function include(arr,obj) {
    return (arr.indexOf(obj) != -1);
}

或在jquery中

$.inArray(value, array)

在回复您的评论时,请检查此link,这也会在评论中解决您的问题。

答案 3 :(得分:1)

但不幸的是,如果你改变你的结构以使用属性,它会快得多。任何其他方法都需要对数组进行迭代,因此总是效率低于下面的方法。

var keyValueObj = {
  someKey: 'someValue',
  nextKey: 'nextValue'
}

// represents 'someValue'
keyValueObj['someKey']

答案 4 :(得分:0)

如果您的键是字符串,则将它们用作对象属性而不是对象数组

如果您的密钥是对象,请使用Map()

答案 5 :(得分:0)

您可以将数组重构为地图,这在设计上有利于快速有效的查找:

{
    'some key': {
        value: 'some value'
    },
    'some other key': {
        value: 'some other value'
    },
}

然后您的select函数将与

一样短
var select = function(what, from) {
    return from[what];
};

如果您希望select()的返回值仍然具有.key属性(这是多余的,因为调用者已将其视为what),则很容易实现要么将key属性保留在地图元素中,要么在返回之前自动添加select()

答案 6 :(得分:0)

如果您需要经常运行此功能,我建议您创建一个索引:

var yourItemList = [{...}],
    select = (function (items) {
        var i = 0,
            l = items.length,
            preparedItems = {};

        for (; i < l; ++i) {
            preparedItems[items[i].key] = items[i].value;
        }

        return function (key) {
            return preparedItems[key];
        };
    }(yourItemList));

这样您只需在项目列表上迭代一次。之后,每个select('theKeyYouNeed')只使用映射的“索引”。

答案 7 :(得分:-1)

你可以filter阵列。它是在Array方法中构建的,因此您不需要声明其他辅助函数

var arr = [
    {
        key: 'some key',
        value: 'some value'
    }, {
        key: 'some key1',
        value: 'some value'
    }
];

arr = arr.filter(function(item) {
    return item.key === 'some key'
});

现在arr只有第一个对象(因为它的键等于'某个键')。您找到的对象是arr[0]

当您只需要一个对象时,可以使用find()代替filter()。请注意,find()是ES6的一部分,并且不支持所有主流浏览器