Filter difference between two objects JS.

huangapple go评论73阅读模式
英文:

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

你可以使用affiliateidartnr的组合作为键,从oldData创建一个Map,然后在FilterObjectDiff函数中迭代newData,检查以下两种情况:

  1. 新的affiliateid/artnr组合是否存在于oldData中;
  2. 如果存在,则检查库存水平是否相同。

如果这两种情况都不成立,那么newData需要更新数据库。

我们使用Map来进行查找,因为查找时间是O(1),因此对于所有newData的查找时间为O(n),其中nnewData的长度。

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

  1. If the new affiliateid/artnr combination exists in oldData; and
  2. 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 =&gt; [`${o.artnr}-${o.affiliateid}`, o.stock ]))

var s

const FilterObjectDiff = (newData) =&gt; newData
  .filter(o =&gt; (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) =&gt; {
      const map = new Map();
      data.forEach(stock =&gt; {
        map.set(`${stock.artnr}:${stock.affiliateid}`, stock);
      });
      return map;
    };
    
    const filterObjDiff = () =&gt; {
      var oldMap = createMap(oldData);
      var newMap = createMap(newData);
      const stockKeys = new Array(oldMap.keys());
      stockKeys.forEach(([key, oldStockData]) =&gt; {
        const newStockData = newMap.get(key);
        if (
          oldStockData.stock != newStockData.stock
        ) {
         console.log(&#39;diff&#39;, newStockData)
        }
      });
   }
   
   filterObjDiff();

<!-- end snippet -->

答案3

得分: 0

Sure, here are the translated parts of your content:

  1. 通过创建从artnraffiliateid生成的唯一ID,通过该唯一ID映射旧数据和新数据,然后比较哈希表中的值

  2. 通过以类似的方式对oldDatanewData进行排序,然后使用两个索引同时迭代两个数组。使用相同的排序函数来确定哪个索引落后于另一个。

这样可以最小化两个数组之间的比较,而且不需要哈希表的内存。

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:

  1. By creating a unique ID from artnr and affiliateid, 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 }) =&gt; 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) =&gt; {
  if(diff[0]?.stock === diff[1]?.stock) return; // these stayed the same
  
  console.log(&quot;%o -&gt; %o&quot;, ...diff);
});

<!-- end snippet -->

  1. by sorting oldData and newData 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) =&gt; a.artnr - b.artnr || a.affiliateid - b.affiliateid;

oldData.sort(order);
newData.sort(order);

const diff = (oldItem, newItem) =&gt; {
  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 &lt; oldData.length &amp;&amp; j &lt; newData.length) {
  const sort = order(oldData[i], newData[j]);
  
       if (sort &lt; 0) diff(oldData[i++], null);  // i has to catch up to j
  else if (sort &gt; 0) diff(null, newData[j++]);  // j has to catch up to i
  else diff(oldData[i++], newData[j++]);        // same artnr &amp;&amp; affiliateid
}
// I&#39;m done with one of the arrays, nothing more to compare. pick up the rest
while (i &lt; oldData.length) diff(oldData[i++], null);
while (j &lt; newData.length) diff(null, newData[j++]);

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年4月19日 16:41:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76052426.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定