簡體   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