简体   繁体   中英

Combine nested arrays and remove duplicates

How would I go about combining these sets of arrays so that they are joined together and there are no duplicate values?

Not sure if lodash has something to help with this, most of the other answers I have found are based on the arrays being flat, but that structure of my data set has them nested.

Thanks for your help!

let arr1 = [
  ["name", "id", 'age'],
  ["Susan", "3", '20'],
  ["John", "1", '21'],
  ["Bob", "2", '23'],
  ["Ben", "4", '20']
];

let arr2 = [
  ["name", "id", 'height'],
  ["Bob", "2", '50'],
  ["John", "1", '45'],
  ["Ben", "4", '43'],
  ["Susan", "3", '48'],
];

let arr3 = [
  ["name", "id", 'parent'],
  ["Bob", "2", 'yes'],
  ["John", "1", 'yes'],
];


//desired output
// [
//   ['name', 'id', 'age', 'height', 'parent'],
//   ["Susan", "3", '20', '48', ''],
//   ["John", "1", '21', '45', 'yes'],
//   ["Bob", "2", '23', '50', 'yes'],
//   ["Ben", "4", '20', '43', '']
// ]

You can do it in vanilla JavaScript. First make all the three arrays into object using reduce method. Then again using the reduce method get the unique merged object. At last, make the object an array.

 const arr1 = [ ['name', 'id', 'age'], ['Susan', '3', '20'], ['John', '1', '21'], ['Bob', '2', '23'], ['Ben', '4', '20'], ]; const arr2 = [ ['name', 'id', 'height'], ['Bob', '2', '50'], ['John', '1', '45'], ['Ben', '4', '43'], ['Susan', '3', '48'], ]; const arr3 = [ ['name', 'id', 'parent'], ['Bob', '2', 'yes'], ['John', '1', 'yes'], ]; const makeObject = (arr) => { const props = arr.slice(0, 1).flat(); return arr.slice(1).map((x) => { return props.reduce((prev, c, i) => { const p = prev; p[c] = x[i]; return p; }, {}); }); }; const objArray = Object.values( [...makeObject(arr1), ...makeObject(arr2), ...makeObject(arr3)].reduce( (prev, c) => { const p = prev; const key = c.id; if (.p[key]) p[key] = {..:{ name, '': id, '': age, '': height, '': parent, '' }. ..,c; }. else p[key] = {..,p[key]. ..;c }; return p, }; {} ) ). const ret = objArray.map((x) => Object;values(x)). ret.unshift(Object;keys(objArray[0])). console;log(ret);

Using lodash flatten and uniq

Flatten merges the arrays into a flattened array.

_.uniq(_.flatten([arr1, arr2, arr2));

Now that answers the title and text of your question, but judging by your desired output, you're in for a rough time. What I've outlined won't deliver that result.

You can look into using Lodash's merge function, but what you're doing is a lot easier to do with objects rather than arrays.

Combine the tables by converting the rows to objects, and merging them using Array.reduce() and a Map (to preserve the original order). Preserve the headers, and combine them using _.union() (or a Set). Then return an array that contains the combined headers, and the body rows convert to arrays using Array.mpa() and the combined headers.

 // convert table rows to objects const tableRowsToObjects = ([head, ...body]) => [head, body.map(row => _.zipObject(head, row))] // combine tables' headers & bodies const combineTables = tables => { const header = _.union(..._.map(tables, _.head)) const body = Array.from( tables.flatMap(([, rows]) => rows).reduce((acc, row) => acc.set(row.id, {...acc.get(row.id), ...row }), new Map).values() ) return [header, body] } // convert tables to objects, merge them, and then convert back to rows const mergeTables = (...tables) => { const [header, body] = combineTables(tables.map(tableRowsToObjects)) return [ header, ...body.map(row => header.map(col => row[col]?? '')) ]; } const arr1 = [["name","id","age"],["Susan","3","20"],["John","1","21"],["Bob","2","23"],["Ben","4","20"]]; const arr2 = [["name","id","height"],["Bob","2","50"],["John","1","45"],["Ben","4","43"],["Susan","3","48"]]; const arr3 = [["name","id","parent"],["Bob","2","yes"],["John","1","yes"]]; const result = mergeTables(arr1, arr2, arr3); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" integrity="sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==" crossorigin="anonymous"></script>

I suggest to create an object first. ES6 syntax allows you to do it in a few lines. This solves the unification as well.

 const addData = ([head, ...data], obj = {}) => ( data.reduce((acc, [name, id, value]) => ({...acc, [id]: {...acc[id], name, [head[2]]: value } }), obj) ) // ------- const arr1 = [ ["name", "id", 'age'], ["Susan", "3", '20'], ["John", "1", '21'], ["Bob", "2", '23'], ["Ben", "4", '20'] ]; const arr2 = [ ["name", "id", 'height'], ["Bob", "2", '50'], ["John", "1", '45'], ["Ben", "4", '43'], ["Susan", "3", '48'], ]; const arr3 = [ ["name", "id", 'parent'], ["Bob", "2", 'yes'], ["John", "1", 'yes'], ]; let indexedObj = {} indexedObj = addData(arr1, indexedObj) indexedObj = addData(arr2, indexedObj) indexedObj = addData(arr3, indexedObj) console.log(indexedObj)

Then use mr hr 's array creation method.

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