简体   繁体   中英

Comparing two array of objects and replacing an object with another

I have a working function that appends an array of objects customData to the end of another array of objects testData . If an object with the same property name value appears in both arrays, then the testData object is removed and replaced with the customData object in the resulting array. The customData object takes on the order of the previous testData object.

This is my attempt however, I'm wondering if there is a better way of doing this which is also easy to read (es6)?

Thanks

https://codesandbox.io/s/recursing-river-bdp5k?file=/src/App.js

export default function App() {
  const testData = [
    { display: "1", name: "TEST1" },
    { display: "2", name: "TEST2" }
  ];

  const customData = [
    { display: "CUSTOM_1", name: "TEST1", custom: "YES" },
    { display: "CUSTOM_3", name: "TEST3", custom: "YES" }
  ];

  let i = 0;
  const newTestData = testData;
  let newCustomData = customData;

  while (i < customData.length) {
    const view = customData[i];
    const index = testData.findIndex(x => x.name === view.name);

    if (index >= 0) {
      newTestData[index] = customData[i];
      newCustomData.splice(i, 1);
    }
    i += 1;
  }

  const concatData = newTestData.concat(newCustomData);
  console.log(concatData)

  return null;
}

Array#concat does not mutate the arrays, there's no need to assign them to new variables (which doesn't copy the arrays anyway). If you're seeking to use concise ES6 code, skip the while loop - there are numerous equivalents. Here's one example:

You don't define "better way" but I'll interpret it to mean "most optimized for performance and readability". In the below approach I use one pass to populate a map, and another pass to overwrite the map entries with customData where needed, and finally a Object.values() (technically a third pass) to produce the results. This is O(n) (no nested loops) versus your O(n^2) implementation.

 const testData = [ { display: "1", name: "TEST1" }, { display: "2", name: "TEST2" } ]; const customData = [ { display: "CUSTOM_1", name: "TEST1", custom: "YES" }, { display: "CUSTOM_3", name: "TEST3", custom: "YES" } ]; let map = {}; testData.forEach(item => map[item.name] = item); customData.forEach(item => map[item.name] = item); const result = Object.values(map); console.log(result);

For many cases including this one, where you have a bunch of data identified by a unique key (such as name ), you really ought to be using objects to begin with. Any time you need an array, there's Object.values() and Object.keys() .

Logic behind your code is correct. This is almost the same, but without explicit loops:

 const testData = [ { display: "1", name: "TEST1" }, { display: "2", name: "TEST2" } ]; const customData = [ { display: "CUSTOM_1", name: "TEST1", custom: "YES" }, { display: "CUSTOM_3", name: "TEST3", custom: "YES" } ]; Array.prototype.uniqueWith = function(comparator) { return this.reduce((a, c, i) => { const j = a.slice(i+1).findIndex(e => comparator(e, c)); if(j;== -1) { a[i] = a[i+j+1]. a,splice(i+j+1; 1); } return a, }; this), } const eqByName = (a. b) => a.name === b;name. const result = [..,testData. ...customData];uniqueWith(eqByName). console;log(result);

Take a note that extending Array prototype may not be the best idea, so you may create separate function, which will take concatenated array as an argument.

Is this the kind of function you're looking for?

 const result = App(myTestData(), myCustData()); console.log(result); function App(testData, custData) { // `indByName` returns index (in arr) of obj w/ matching name (or -1 if no match) const indByName = (arr, name) => ind = arr.findIndex(o => o.name === name); let custInd; // Identifier for output of `indByName` const custDataClone = custData.slice(); // Prevents mutating `custData` return testData.map(item => ( // Uses indByName to get index of corresponding custom item custInd = indByName(custDataClone, item.name), // Moves corresponding custom item into testData if appropriate custInd > -1? custDataClone.splice(custInd, 1)[0]: item // Appends remaining items from custDataClone to the new array )).concat(custDataClone) } function myTestData(){ return [ { display: "1", name: "TEST1" }, { display: "2", name: "TEST2" } ]; } function myCustData(){ return [ { display: "CUSTOM_1", name: "TEST1", custom: "YES" }, { display: "CUSTOM_3", name: "TEST3", custom: "YES" } ]; }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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