英文:
Filter difference between two objects JS
问题
I try to find the most effective way to compare two arrays of objects and return filtered difference in JavaScript.
我试图找到在JavaScript中比较两个对象数组并返回过滤差异的最有效方法。
I build an app to update stock in DB. But this app can use many users in the same time. I would like to avoid calling API and refresh all data in app each time changes are made, bcz database is too big and loading time is long. I have and old data locally, with help of MQTT I receive new data the moment its updated by someone. The goal is to find the difference between two objects and update locally only the one that has changes. Objects looks like this:
我构建了一个用于更新数据库库存的应用程序。但是,这个应用程序可以同时被多个用户使用。我希望避免每次进行更改时调用API并刷新应用程序中的所有数据,因为数据库太大,加载时间很长。我在本地有旧数据,借助MQTT的帮助,我会在有人更新数据时立即接收到新数据。目标是找到两个对象之间的差异,并仅在本地更新具有更改的对象。对象看起来像这样:
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 15 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 20 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
The only way I can think about it's foreach. But in real life each of arrays will contain thousands of objects, so I would like to avoid iterations type of: (my working func)
我能想到的唯一方法是使用forEach
。但在现实生活中,每个数组都将包含数千个对象,所以我想避免迭代类型的操作:(我的工作函数)
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
const filterObjDiff = () => {
var obj1 = oldData as StockUpdate.stockMqttResponse[]
var obj2 = newData as StockUpdate.stockMqttResponse[]
obj1.forEach(oldD => {
obj2.forEach(newD => {
if (
oldD.affiliateid == newD.affiliateid &&
oldD.artnr == newD.artnr &&
oldD.stock != newD.stock
) {
console.log('diff', newD)
}
})
})
}
Is there an effective way to white func
是否有一种有效的方式可以编写如下函数:
const FilterObjectDiff = (oldData, newData) => {
// filter here without iterations
return [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 20 }
]
}
I would appreciate any ideas.
我会感激任何想法。
英文:
I try to find the most effective way to compare two arrays of objects and return filtered difference in JavaScript.
I build an app to update stock in DB. But this app can use many users in the same time. I would like to avoid calling API and refresh all data in app each time changes are made, bcz database is too big and loading time is long. I have and old data locally, with help of MQTT I receive new data the moment its updated by someone. The goal is to find the difference between two objects and update locally only the one that has changes. Objects looks like this:
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 15 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 20 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
The only way I can think about it's foreach. But in real life each of arrays will contain thousands of objects, so I would like to avoid iterations type of: (my working func)
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
const filterObjDiff = () => {
var obj1 = oldData as StockUpdate.stockMqttResponse[]
var obj2 = newData as StockUpdate.stockMqttResponse[]
obj1.forEach(oldD => {
obj2.forEach(newD => {
if (
oldD.affiliateid == newD.affiliateid &&
oldD.artnr == newD.artnr &&
oldD.stock != newD.stock
) {
console.log('diff', newD)
}
})
})
}
Is there an effective way to white func
const FilterObjectDiff = (oldData, newData) => {
// filter here without iterations
return [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 20 }
]
}
I would appreciate any ideas.
答案1
得分: 2
你可以使用affiliateid
和artnr
的组合作为键,从oldData
创建一个Map
,然后在FilterObjectDiff
函数中迭代newData
,检查以下两种情况:
- 新的
affiliateid
/artnr
组合是否存在于oldData
中; - 如果存在,则检查库存水平是否相同。
如果这两种情况都不成立,那么newData
需要更新数据库。
我们使用Map
来进行查找,因为查找时间是O(1)
,因此对于所有newData
的查找时间为O(n)
,其中n
是newData
的长度。
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 15 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 20 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 1, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let oldMap = new Map(oldData.map(o => [`${o.artnr}-${o.affiliateid}`, o.stock ]))
var s
const FilterObjectDiff = (newData) => newData
.filter(o => (s = oldMap.get(`${o.artnr}-${o.affiliateid}`)) ?
s != o.stock :
true)
console.log(FilterObjectDiff(newData))
英文:
You could create a Map
from oldData
using a combination of affiliateid
and artnr
as the key, and then iterate newData
in your FilterObjectDiff
function, checking
- If the new
affiliateid
/artnr
combination exists inoldData
; and - If it does, if the stock level is the same
If neither of these cases are true, then the newData
needs to update the DB.
We use a Map
as lookup time is O(1)
and thus the lookup time for all of newData
is O(n)
where n
is the length of newData
.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 15 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 20 },
{ artnr: 12, affiliateid: 3, stock: 1 },
{ artnr: 13, affiliateid: 1, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let oldMap = new Map(oldData.map(o => [`${o.artnr}-${o.affiliateid}`, o.stock ]))
var s
const FilterObjectDiff = (newData) => newData
.filter(o => (s = oldMap.get(`${o.artnr}-${o.affiliateid}`)) ?
s != o.stock :
true)
console.log(FilterObjectDiff(newData))
<!-- end snippet -->
答案2
得分: 1
我认为提高性能最简单的方法是使用哈希映射,因为它是在特定键下查找特定值的O(1)。我已经用哈希映射重构了它,它是等价的。
英文:
I think the easiest way to improve the performance is with Hash Map since it's O(1) of finding the specific value with a key. I've refactored it with Hash Map and it's equivalent.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
const createMap = (data) => {
const map = new Map();
data.forEach(stock => {
map.set(`${stock.artnr}:${stock.affiliateid}`, stock);
});
return map;
};
const filterObjDiff = () => {
var oldMap = createMap(oldData);
var newMap = createMap(newData);
const stockKeys = new Array(oldMap.keys());
stockKeys.forEach(([key, oldStockData]) => {
const newStockData = newMap.get(key);
if (
oldStockData.stock != newStockData.stock
) {
console.log('diff', newStockData)
}
});
}
filterObjDiff();
<!-- end snippet -->
答案3
得分: 0
Sure, here are the translated parts of your content:
-
通过创建从
artnr
和affiliateid
生成的唯一ID,通过该唯一ID映射旧数据和新数据,然后比较哈希表中的值 -
通过以类似的方式对
oldData
和newData
进行排序,然后使用两个索引同时迭代两个数组。使用相同的排序函数来确定哪个索引落后于另一个。
这样可以最小化两个数组之间的比较,而且不需要哈希表的内存。
Please note that I've only provided translations for the code comments and descriptions, as you requested. If you have any specific questions or need further assistance, please feel free to ask.
英文:
Two approaches:
- By creating a unique ID from
artnr
andaffiliateid
, mapping the old and the new data by that unique id and compare the values in that hashmap
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 }
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 3, stock: 2 }
]
// use an object as a hashmap
const map = {};
const getOrCreateEntry = ({ artnr, affiliateid }) => map[`${artnr}:${affiliateid}`] ??= [null, null];
// fill the hashmap
for (const item of oldData) getOrCreateEntry(item)[0] = item; // old item
for (const item of newData) getOrCreateEntry(item)[1] = item; // new item
Object.values(map).forEach((diff) => {
if(diff[0]?.stock === diff[1]?.stock) return; // these stayed the same
console.log("%o -> %o", ...diff);
});
<!-- end snippet -->
- by sorting
oldData
andnewData
in a similar way, then using two indices to iterate over both arrays at the same time. Using the same sort function to determine which index is behind the other.
This minimizes the comparisons between the two arrays and doesn't require the memory of a hashmap.
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
let oldData = [
{ artnr: 12, affiliateid: 1, stock: 10 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 2, stock: 2 },
]
let newData = [
{ artnr: 12, affiliateid: 1, stock: 11 },
{ artnr: 12, affiliateid: 2, stock: 1 },
{ artnr: 13, affiliateid: 3, stock: 2 },
]
const order = (a,b) => a.artnr - b.artnr || a.affiliateid - b.affiliateid;
oldData.sort(order);
newData.sort(order);
const diff = (oldItem, newItem) => {
if (oldItem?.stock === newItem?.stock) return;
console.log(oldItem, newItem);
}
// two indices one for oldData, one for newData
let i = 0, j = 0;
while (i < oldData.length && j < newData.length) {
const sort = order(oldData[i], newData[j]);
if (sort < 0) diff(oldData[i++], null); // i has to catch up to j
else if (sort > 0) diff(null, newData[j++]); // j has to catch up to i
else diff(oldData[i++], newData[j++]); // same artnr && affiliateid
}
// I'm done with one of the arrays, nothing more to compare. pick up the rest
while (i < oldData.length) diff(oldData[i++], null);
while (j < newData.length) diff(null, newData[j++]);
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论