繁体   English   中英

通过数组过滤出JSON

[英]Filtering out JSON by an array

我有一个JSON文件

{
    "data": [
        {
            "name": "Jake",
            "id": "123"
        },
        {
            "name": "Bob",
            "id": "234"
        }]
}

具有所有ID的唯一标识,并说我有一个被禁止的ID [[123“,” 423“]数组,我想删除该数组中具有ID号的所有条目(例如,作为输出,我想要以下内容)。

{
    "data": [
        {
            "name": "Bob",
            "id": "234"
        }]
}

如果JSON和数组中有几千个条目,那么一种中等有效的方法(在普通计算机上运行几秒钟)来实现这一目标?

您可以将Array.prototype.filter()方法与.indexOf()结合使用:

 var bannedIds = ["123", "423"]; var input = { "data": [ { "name": "Jake", "id": "123" }, { "name": "Bob", "id": "234" }] }; input.data = input.data.filter(function(v) { return bannedIds.indexOf(v.id) === -1; }); console.log(input); 

如果您不想覆盖原始数组,则只需将.filter()调用的结果分配给新变量。

如果上面原来是与你的大数据量的速度太慢,你可以尝试更换.filter()与传统for循环,和/或更换.indexOf()与取缔ID的阵列中创建一个查询对象。

如果可以使用ES6,则可以执行以下操作:

 const source = { "data": [ { "name": "Jake", "id": "123" }, { "name": "Bob", "id": "234" } ] }; const banned = ["123", "423"]; // O(n) startup cost for constant access time later const bannedSet = new Set(banned); // O(n) const result = source.data.filter(x => !bannedSet.has(x.id)); console.log(result); 

如评论中所述,创建Set产生启动成本。 但是,这使您可以随后调用Set.prototype.has ,它是恒定的。

然后,只需遍历每个元素并过滤掉禁区内的元素即可。

如果您不能使用ES6,则可以将Set替换为普通的JS对象。 如果必须支持IE <9,请对Array.prototype.filter使用polyfill(感谢@nnnnnn)。

UPDATE

@SpencerWieczorek指出, ES6规范似乎表明Set.prototype.hasSet.prototype.has迭代。 我过早地谈到查找是恒定的(我从其他语言继承了我的经验)。 通常,根据基础实现,集合的性能将优于O(n),例如常量或O(log n)。 您的里程可能会有所不同,因此在某些情况下nnnnnn的回答可能会更快。

在此处尝试一些具有大量数据的解决方案以进行确认。

编辑

我回避使用filter之类的方法,因为这涉及创建一个新的数组。 对于我们正在讨论的数据大小,这实际上可能很好,但是我下面使用的方法更加有效。


在我的笔记本电脑上,整个程序运行约0.2秒。 (它使用10,000个条目和100个禁止的ID。)

var o = {
    data: []
};

for (var i = 0; i < 10000; i++) {
    o.data.push({
        name: i % 2 === 0 ? 'Jake' : 'Bob', // couldn't think of more names :-)
        id: ''+i // convert to string
    });
}

var banned = {};

for (var i = 0; i < 100; i++) {
    banned[''+(i * 3)] = true; // ban 0, 3, 6, 9, 12, ...
}

for (var i = o.data.length - 1; i >= 0; i--) {
    if (banned[o.data[i].id]) {
        o.data.splice(i, 1);
    }
}

console.log(o);

// { data:
//    [ { name: 'Bob', id: '1' },
//      { name: 'Jake', id: '2' },
//      { name: 'Jake', id: '4' },
//      { name: 'Bob', id: '5' },
//      { name: 'Bob', id: '7' },
//      { name: 'Jake', id: '8' },
//      { name: 'Jake', id: '10' },
//      ...

我假设您已经解析了JSON数据,并且有一个变量指向要过滤的数组。 另外,您还有一个带有“禁止” ID的数组。

var data = [{
        "name": "Jake",
        "id": "123"
    }, {
        "name": "Bob",
        "id": "234"
    }, {
        "name": "Joe",
        "id": "345"
    }];

var banned = ["123", "345"];

以下功能可能会在性能方面做得最好:

// Modifies the data array "in place", removing all elements
// whose IDs are found in the "banned" array
function removeBanned(data, banned) {
    // Index the "banned" IDs by writing them as the properties
    // of a JS object for really quick read access later on
    var bannedObj = {};
    banned.forEach(function(b) { bannedObj[b] = true; });

    var index = data.length - 1;

    while (index >= 0) {
        if (bannedObj[data[index].id]) {
            data.splice(index, 1);
        }
        --index;
    }
}

这似乎足够快,但是我建议您制作一个免费的干净副本,而不要修改现有阵列,这可能会更快。

 function filterout(o,p,f) { var i = 0; f = f.join(); while( o[i] ) { if( f.match( o[i][p] ) ){ o.splice(i,1) } i++ }; } var filter = ["123","423"]; var object = { "data": [ { "name": "John", "id": "723" }, { "name": "Jake", "id": "123" }, { "name": "Bob", "id": "234" }] }; filterout( object.data, "id", filter ); console.log(JSON.stringify( object )); 

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM