[英]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.has
。 Set.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.