Javascript merge two objects based on key - javascript

I have some objects in the shape of below.
[{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}]
I want to merge objects into one single object in the array if key pair (product, and productId) are mathced, in the below format.
[{
product: 'ABC',
productId: 'AB123',
batch: ['BA1', 'BA2'],
price: ['12', '15']
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}]
How can I do it in lodash or in pure javascript.

This proposal does not alter the given data.
It creates new objects, first with just single data, later if more data should be grouped, it uses an array for batch and price.
var data = [{ product: 'ABC', productId: 'AB123', batch: 'BA1', price: '12' }, { product: 'ABC', productId: 'AB123', batch: 'BA2', price: '15' }, { product: 'XYZ', productId: 'AB124', batch: 'XY1', price: '124'}],
merged = [];
data.forEach(function (a) {
if (!this[a.productId]) {
this[a.productId] = { product: a.product, productId: a.productId, batch: a.batch, price: a.price };
merged.push(this[a.productId]);
return;
}
if (!Array.isArray(this[a.productId].batch)) {
this[a.productId].batch = [this[a.productId].batch];
}
if (!Array.isArray(this[a.productId].price)) {
this[a.productId].price = [this[a.productId].price];
}
this[a.productId].batch.push(a.batch);
this[a.productId].price.push(a.price);
}, Object.create(null));
console.log(merged);

You can make use of _.uniqWith to loop over the collection and get rid of duplicates. Apart from that, uniqWith grants you access to the objects themselves so you can tamper them as you like.
In this case, when a duplicate is found, I add its batch and price to the array of the original object, getting the desired result.
var arr = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}];
function addToArray(val1, val2) {
return _.isArray(val1) ? val1.concat(val2) : [val1].concat(val2);
}
function modifyObjs(a, b) {
b.batch = addToArray(b.batch, a.batch);
b.price = addToArray(b.price, a.price);
return true;
}
function predicateAndModifier(a, b) {
return a.product === b.product && a.productId === b.productId && modifyObjs(a, b);
}
console.log(_.uniqWith(arr, predicateAndModifier));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

Lodash 4.17.2
_.reduce(data, function(result, item) {
var added = _.find(result, {
product: item.product,
productId: item.productId
});
if (_.isObject(added)) {
//!! better to merge with new object and add result to array again to avoid mutable
added = _.mergeWith(added, item, function(addedVal, itemVal, key) {
if (key === 'product' || key === 'productId') {
return addedVal;
}
return _.concat(addedVal, itemVal);
});
return result;
}
return _.concat(result, item);
}, []);

You can merge similar objects in the array using a lodash's chain with _.transform() and _.mergeWith():
function mergeSimilar(arr, arrayProps) {
// transform the array into a map object
return _(arr).transform(function(result, item) {
// create a temp id that includes the product and productId
var id = item.product + item.productId;
// merge the existing item with a new item
result[id] = _.mergeWith(result[id] || {}, item, function(objValue, srcValue, key) {
// if a value exists, and it's one of the request keys, concat them into a new array
if (!_.isUndefined(objValue) && _.includes(arrayProps, key)) {
return [].concat(objValue, srcValue);
}
});
}, {})
.values() // get the values from the map object
.value();
}
var arr = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}];
var result = mergeSimilar(arr, ['batch', 'price']);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>

Does it have to be readable?
var data = [{
product: 'ABC',
productId: 'AB123',
batch: 'BA1',
price: '12'
}, {
product: 'ABC',
productId: 'AB123',
batch: 'BA2',
price: '15'
}, {
product: 'ABC',
productId: 'AB113',
batch: 'BA2',
price: 15
}, {
product: 'XYZ',
productId: 'AB124',
batch: 'XY1',
price: '124'
}]
var unEs6 = function(x) {
if (x instanceof Map) {
var result = {}
for (let [key, value] of x.entries()) {
result[key] = unEs6(value);
}
return result;
}
else {
return x
}
}
JSON.stringify(unEs6(
data
.map(
row => (new Map().set(
row.product, new Map().set(
row.productId, new Map()
.set("batch", [row.batch])
.set("price", [row.price])
)
)
)
)
.reduce((a, b) => !a.has(b.keys().next().value) ?
new Map([...a, ...b]) :
!a.get(b.keys().next().value).has(b.get(b.keys().next().value).keys().next().value) ?
a.set(b.keys().next().value, new Map([
...a.get(b.keys().next().value),
...b.get(b.keys().next().value)
])) :
a.set(b.keys().next().value, a.get(b.keys().next().value).set(
b.get(b.keys().next().value).keys().next().value,
new Map()
.set("batch", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch")
.concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("batch"))
)
.set("price", a.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price")
.concat(b.get(b.keys().next().value).get(b.get(b.keys().next().value).keys().next().value).get("price"))
)
))
)
))

Related

Process array of objects to return least priced per product using JavaScript

Given an array of objects, containing products. A single object contains a single product offer.
Products can have a identical productId, while offerId are unique for each product.
Process the data to get the cheapest priced item for each offer
const data = [
{ productId: 'dhdiwu', offerId: 'd3en', price: '$12.20' },
{ productId: 'dhdiwu', offerId: 's2dr', price: '$8.45' },
{ productId: 'dhdiwu', offerId: 'hy38', price: '$21.21' },
{ productId: 'dowksm', offerId: 'ie8u', price: '$1.77' },
{ productId: 'dowksm', offerId: 'djs3', price: '$24.21' },
{ productId: 'dowksm', offerId: 'pies', price: '$92.36' },
{ productId: 'bdbhsu', offerId: '9wid', price: '$100.98' }
]
const dataArray = data.reduce((prev, t, index, arr) => {
if (typeof prev[t.productId] === 'undefined') {
prev[t.productId] = [];
}
prev[t.productId].push(t);
return prev;
}, {});
let same_id = []
let cheapest = []
Object.keys(dataArray).forEach(i => {
same_id.push(dataArray[i]);
});
console.log(same_id)
//output for now
/*[
[
{ productId: 'dhdiwu', offerId: 'd3en', price: '$12.20' },
{ productId: 'dhdiwu', offerId: 's2dr', price: '$8.45' },
{ productId: 'dhdiwu', offerId: 'hy38', price: '$21.21' }
],
[
{ productId: 'dowksm', offerId: 'ie8u', price: '$1.77' },
{ productId: 'dowksm', offerId: 'djs3', price: '$24.21' },
{ productId: 'dowksm', offerId: 'pies', price: '$92.36' }
],
[ { productId: 'bdbhsu', offerId: '9wid', price: '$100.98' } ]
]*/
I would first start by grouping the products by productId, something like what is suggested here should work: Most efficient method to groupby on an array of objects
function groupByKey(array, key) {
const groupedObject = {}
for (const item of array) {
const value = item[key]
if (groupedObject[value] === undefined) {
groupedObject[value] = []
}
groupedObject[value].push(item)
}
return groupedObject
}
groupByKey(data, 'productId')
Now you have an object with three properties, the unique productID's with each product inside it. Then loop through each one, find the lowest price.
const grouped = groupByKey(data, 'productId');
const lowest = {};
for (const group of Object.keys(grouped)) {
if (!lowest[group]) {
lowest[group] = '';
}
for (const product of grouped[group]) {
if (lowest[group] === '') {
lowest[group] = product.price
}
if (product.price < lowest[group]) {
lowest[group] = product.price;
}
}
}
console.log(lowest);
// {dhdiwu: '$12.20', dowksm: '$1.77', bdbhsu: '$100.98'}
It's a little scrappy, and I'm sure there are some cool one-liners you could build, but that's the general idea.
If I understand correctly, you're looking to find the lowest priced offer for each productId.
You can go with this:
const data = [
{ productId: 'dhdiwu', offerId: 'd3en', price: '$12.20' },
{ productId: 'dhdiwu', offerId: 's2dr', price: '$8.45' },
{ productId: 'dhdiwu', offerId: 'hy38', price: '$21.21' },
{ productId: 'dowksm', offerId: 'ie8u', price: '$1.77' },
{ productId: 'dowksm', offerId: 'djs3', price: '$24.21' },
{ productId: 'dowksm', offerId: 'pies', price: '$92.36' },
{ productId: 'bdbhsu', offerId: '9wid', price: '$100.98' }
]
// group by productId and find the lowest price
const result = data.reduce((acc, { productId, offerId, price }) => {
const current = acc[productId]
if (!current || current.price > price) {
acc[productId] = { offerId, price }
}
return acc
}, {})
console.log(result)
output:
node .\scratch.js
{
dhdiwu: { offerId: 'd3en', price: '$12.20' },
dowksm: { offerId: 'ie8u', price: '$1.77' },
bdbhsu: { offerId: '9wid', price: '$100.98' }
}

How to loop through two arrays of objects and get a new array with some data modified?

How to loop through two arrays of objects and get a new array with some data modified?
Arrays:
const products = [
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Tees',
},
];
const categories = [
{
name: 'Jeans',
},
{
name: 'Tees',
},
];
Need new categories array like this with new prop productCount:
const newCategories = [
{
name: 'Jeans',
productCount: 2,
},
{
name: 'Tees',
productCount: 0,
},
];
I tried this way but it doesn't work:
const newArr = categories.map((category) => {
let count = 0;
const index = products.findIndex((product) => category.name === product.category);
if (index > -1) {
return {
...category,
productCount: count++,
};
}
return {
...category,
productCount: 0,
};
});
Increasing the count number will not in that case because it will always start with zero. Instead, you can use the filter() method to find the number of products with a specific category and assign this number to productCount attribute.
const products = [{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Tees',
},
];
const categories = [{
name: 'Jeans',
},
{
name: 'Tees',
},
];
const newArr = categories.map((category) => {
const numberOfItems = products.filter((product) => category.name === product.category);
return {
...category,
productCount: numberOfItems.length,
};
});
console.log(newArr)
You can create an object and the transform it to array, something like this:
const products = [
{
brand: "Levis",
category: "Jeans"
},
{
brand: "Levis",
category: "Jeans"
},
{
brand: "Levis",
category: "Tees"
}
];
const categoriesObj = {};
products.forEach(({ brand, category }) => {
categoriesObj[category] ??= {
name: category,
productCount: 0
};
++categoriesObj[category].productCount;
});
const newCategories = Object.values(categoriesObj);
console.log(newCategories);
You can use the Array#Map method and add a productCount property using the Array#filter method
const products = [{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Jeans',
},
{
brand: 'Levis',
category: 'Tees',
},
];
const categories = [{
name: 'Jeans',
},
{
name: 'Tees',
},
];
const newCategories = [...categories].map(category => ({
...category,
productCount: products.filter(product => product.category === category.name).length
}))
console.log(newCategories)
You could do this with Array.reduce(), incrementing the productCount for each item. This should also be efficient, requiring only one iteration of the products array.
We'd run the reduce over both arrays, ensuring that we'll end up with a productCount of zero where no products for that category exist.
const products = [ { brand: 'Levis', category: 'Jeans', }, { brand: 'Levis', category: 'Jeans', }, { brand: 'Levis', category: 'Tees', }, ];
const categories = [ { name: 'Jeans', }, { name: 'Tees', }, { name: 'Foo', } ];
const result = Object.values([...categories, ...products].reduce((acc, { brand, category, name }) => {
const key = name || category;
acc[key] = acc[key] || { name: key, productCount: 0 };
if (category) acc[key].productCount++;
return acc;
}, {}));
console.log('Result:', result);
.as-console-wrapper { max-height: 100% !important; }

Merge all keys into single object with the same Id in JavaScript

I have an array of objects Like that.
var orderResults = [{
id: '1',
name: 'Maya Mahardhani',
payment_amount : 100,
sku: 'ST001802027',
seq: '1'
},
{
id: '1',
name: 'Maya Mahardhani',
payment_amount : 50,
sku: 'ST000703044',
seq: '2'
},
{
id: '2',
name: 'Tara Debu Batara',
payment_amount : 100,
sku: 'ST005101001',
seq: '1'
},
{
id: '3',
name: 'Nikita Gigir',
payment_amount : 100,
sku: 'ST004403030',
seq: '1'
}]
But I am trying to extract the data in the following way.
[{
id: '1',
name: 'Maya Mahardhani',
total_amount : 150,
sku_1: 'ST001802027',
sku_2: 'ST000703044',
},
{
id: '2',
name: 'Tara Debu Batara',
total_amount : 100,
sku_1: 'ST005101001'
},
{
id: '3',
name: 'Nikita Gigir',
total_amount : 100,
sku_1: 'ST004403030'
}]
I give try with the reduce function of JavaScript. But it overwrites the prev key with the old one. My Code Snippet is like that. I think I am closer to solve. But still seeking the help
orderResults.reduce((res, obj) => {
res[obj.id] = {
total_amount : (obj.id in res ? res[obj.id].total_amount : 0) + obj.payment_amount,
name : obj.name,
}
res[obj.id]['sku' + obj.seq]= obj.sku
return res;
},[])
Thank you
Do not create a new object every time.
const result = Object.values(orderResults.reduce((res, obj) => {
res[obj.id] = res[obj.id] ||
{
id: obj.id,
total_amount : 0,
name : obj.name,
};
res[obj.id].total_amount += obj.total_amount;
res[obj.id]['sku' + obj.seq] = obj.sku;
return res;
},[]))
I think this will do what you are trying to do:
orderResults.reduce((res, obj, i) => {
const existingIdx = res.findIndex(r => r.id === obj.id)
if (existingIdx > -1) {
res[existingIdx] = {
...res[existingIdx],
total_amount : res[existingIdx].total_amount ? res[existingIdx].total_amount + obj.payment_amount : res[existingIdx].payment_amount + obj.payment_amount,
name : obj.name,
['sku_' + obj.seq]: obj.sku
}
} else {
res.push({
id: obj.id,
name: obj.name,
total_amount: obj.payment_amount,
['sku_' + obj.seq]: obj.sku
})
}
return res;
},[])
Notice this line will preserve the original object and overwrite any duplicate keys that are defined afterwards:
...res[existingIdx],
Also when your code runs this line:
res[obj.id] = {
it is setting a specific index in the array, which I don't think you want to do. You want to either push (if the object id hasn't been added yet), or overwrite the existing object at the original insertion point when the object with the same id was created.
[{
id: '1',
name: 'Maya Mahardhani',
payment_amount: 100,
sku: 'ST001802027',
seq: '1'
},
{
id: '1',
name: 'Maya Mahardhani',
payment_amount: 50,
sku: 'ST000703044',
seq: '2'
},
{
id: '2',
name: 'Tara Debu Batara',
payment_amount: 100,
sku: 'ST005101001',
seq: '1'
},
{
id: '3',
name: 'Nikita Gigir',
payment_amount: 100,
sku: 'ST004403030',
seq: '1'
}].reduce((acc, current) => {
const { id, name, payment_amount, sku, seq } = current;
const previousRecord = acc[id];
if (typeof previousRecord === 'object') {
return {
...acc,
[id]: {
...previousRecord,
[`sku_${seq}`]: sku,
total_amount: previousRecord.total_amount + payment_amount
}
}
} else {
return {
...acc,
[id]: {
id,
name,
[`sku_${seq}`]: sku,
total_amount: payment_amount
}
}
}
}, {}) // returns an Object; use Object.values to convert to a list

Group object keys with accumalated value in new Array in JavaScript

I have an array of objects like this:
[
{
item: 'abc',
category: 'car',
price: 1000
},
{
item: 'abc',
category: 'bike',
price: 1000
},
{
item: 'abc',
category: 'car',
price: 2000
},
{
item: 'abc',
category: 'car',
price: 3000
},
{
item: 'abc',
category: 'bike',
price: 500
},
{
item: 'abc',
category: 'plane',
price: 9000
},
]
I want to create a new Array from above array which groups objects by category and has total price for that category as value for 'price' key:
[
{
category: car,
price: 6000
},
{
category: bike,
price: 1500
},
{
category: plane,
price: 9000
}
]
How can I do this in Javascript?
Basic approach is
create a map first with category as key and price as value
convert this map into an array
DEMO
var input = [
{
item: 'abc',
category: 'car',
price: 1000
},
{
item: 'abc',
category: 'bike',
price: 1000
},
{
item: 'abc',
category: 'car',
price: 2000
},
{
item: 'abc',
category: 'car',
price: 3000
},
{
item: 'abc',
category: 'bike',
price: 500
},
{
item: 'abc',
category: 'plane',
price: 9000
},
];
var map = {};
input.forEach( function ( item ){
map [ item.category ] = map [ item.category ] || 0;
map [ item.category ] += item.price;
});
var output = Object.keys( map ).map( function(key){ return { category: key, price : map[key] } });
console.log( output );
You could group it with a hash table and take it as reference for adding the values.
Main structure:
grouped = data.reduce(function (hash) { // closure over hash
return function (r, a) { /* ... */ }; // returns function for callback
}(Object.create(null)), []); // call of IFFE with an empty object
The main idea is to use a variable hash outside of the global context, but usable inside of the callback for Array#reduce.
This works with an IIFE (Immediately Invoked Function Expression), which is a function which is directly after declaration invoked with an empty object.
This creates the variable hash with an empty object and returns the function for the callback.
Inside of the callback:
The callback works with two variables, r and a.
function (r, a) {
// business logic
return r;
}
At start, variable r gets the initialValue, of an empty array []. In this array, the result set is collected and returned for every iteration. This parameter is describes as accumulator.
Parameter a is the current value of the array. This is a single object, like
{
item: 'abc',
category: 'car',
price: 1000
}
and only one object is being processed at the same time.
Basically this solution works with an object and it looks at the end like this
{
car: {
category: "car",
price: 6000
},
bike: {
category: "bike",
price: 1500
},
plane: {
category: "plane",
price: 9000
}
}
where the properties, like car or bike give the reference to the result array without the property car or bike.
At first, a check is made, if the category exists in the hash table. If not, then a new object is created with category and a price with zero, because the price property gets updated for every item within the same category. Then the new object reference gets pushed to the result array.
After the check, the property exist already or is just created, the price property gets an update with the actual value.
At last, the result set is returned for the next update iteration or as final result.
var data = [{ item: 'abc', category: 'car', price: '1000' }, { item: 'abc', category: 'bike', price: '1000' }, { item: 'abc', category: 'car', price: '2000' }, { item: 'abc', category: 'car', price: '3000' }, { item: 'abc', category: 'bike', price: '500' }, { item: 'abc', category: 'plane', price: '9000' }],
grouped = data.reduce(function (hash) {
return function (r, a) {
if (!hash[a.category]) {
hash[a.category] = { category: a.category, price: 0 };
r.push(hash[a.category]);
}
hash[a.category].price += +a.price;
return r;
};
}(Object.create(null)), []);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var data = [{item: 'abc',category: 'car',price: 1000},{item:'abc',category: 'bike',price: 1000},{item: 'abc',category: 'car',price: 2000},{item: 'abc',category: 'car',price: 3000},{item: 'abc',category: 'bike',price: 500},{item: 'abc',category: 'plane',price: 9000}];
var groupArr = [];
var res = data.reduce(function(all, item, index){
var i = groupArr.findIndex(x => x.category == item.category);
if(i <= -1)
groupArr.push({category: item.category, price: item.price});
else
groupArr[i].price += item.price;
return all;
},{})
console.log(groupArr)
See this if this helps
var obj = [{
item: 'abc',
category: 'car',
price: 1000
}, {
item: 'abc',
category: 'bike',
price: 1000
}, {
item: 'abc',
category: 'car',
price: 2000
}, {
item: 'abc',
category: 'car',
price: 3000
}, {
item: 'abc',
category: 'bike',
price: 500
}, {
item: 'abc',
category: 'plane',
price: 9000
}]
var newobj = {};
obj.forEach(function(record) {
newobj[record.category] = {
category: record.category,
price : newobj[record.category] && newobj[record.category].price ? newobj[record.category].price + record.price : record.price
}
})
var result = [];
Object.keys(newobj).forEach(function(key) {
result.push(newobj[key])
})
console.log(result);

Two collections to form one collection that replaces duplicates with updated field

I have two unique collections that look something like this:
Collection one:
[
{
id: 123,
Name: Ben,
Type: Car
},
{
id: 124,
Name: Morgan,
Type: Van
},
{
id: 125,
Name: Josh,
Type: Bus
}
]
Collection two:
[
{
id: 123,
Name: Ben,
Type: House
},
{
id: 124,
Name: Morgan,
Type: Flat
},
{
id: 126,
Name: Jack,
Type: Landrover
}
]
I have made sure there are no duplicates in both collections, using lodash _.uinqBy.
However I want to merge the two together to create one collection but replace the ones with matching ids with the ones where the type is === "Car" || === "Van"
so therefor the result I would have from the above collections would be:
Result:
[
{
id: 123,
Name: Ben,
Type: Car
},
{
id: 124,
Name: Morgan,
Type: Van
},
{
id: 125,
Name: Josh,
Type: Bus
},
{
id: 126,
Name: Jack,
Type: Landrover
}
]
Anyway I can do this using lodash? Or any other way?
Thanks in advance :)
Using lodash:
function unite(arr1, arr2) {
return _(arr1)
.concat(arr2) // concat the arrays
.groupBy('id') // create a group by the id
.map(function(group) { // in each group
return _.find(group, function(item) { // find if one contains the request Type, and if not return the 1st in the group
return item.Type === 'Car' || item.Type === 'Van';
}) || _.head(group);
})
.values() // exract the values
.value();
}
function unite(arr1, arr2) {
return _(arr1)
.concat(arr2) // concat the arrays
.groupBy('id') // create a group by the id
.map(function(group) { // in each group
return _.find(group, function(item) { // find if one contains the request Type, and if not return the 1st in the group
return item.Type === 'Car' || item.Type === 'Van';
}) || _.head(group);
})
.values() // exract the values
.value();
}
var arr1 = [{
id: '123',
Name: 'Ben',
Type: 'Car'
}, {
id: '124',
Name: 'Morgan',
Type: 'Flat'
}, {
id: '125',
Name: 'Josh',
Type: 'Bus'
}];
var arr2 = [{
id: '123',
Name: 'Ben',
Type: 'House'
}, {
id: '124',
Name: 'Morgan',
Type: 'Van'
}, {
id: '126',
Name: 'Jack',
Type: 'Landrover'
}];
var result = unite(arr1, arr2);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.2/lodash.min.js"></script>
Using ES6 Map and spread:
const uniqueUnion = (arr1, arr2) => [
...arr1.concat(arr2)
.reduce((m, item) => {
if(!m.has(item.id) || item.Type === 'Car' || item.Type === 'Van') {
m.set(item.id, item);
}
return m;
}, new Map()).values()
];
const unite = (arr1, arr2) => [
...arr1.concat(arr2)
.reduce((m, item) => {
if (!m.has(item.id) || item.Type === 'Car' || item.Type === 'Van') {
m.set(item.id, item);
}
return m;
}, new Map()).values()
];
const arr1 = [{
id: '123',
Name: 'Ben',
Type: 'Car'
}, {
id: '124',
Name: 'Morgan',
Type: 'Flat'
}, {
id: '125',
Name: 'Josh',
Type: 'Bus'
}];
const arr2 = [{
id: '123',
Name: 'Ben',
Type: 'House'
}, {
id: '124',
Name: 'Morgan',
Type: 'Van'
}, {
id: '126',
Name: 'Jack',
Type: 'Landrover'
}];
const result = unite(arr1, arr2);
console.log(result);
This is a proposal in plain javascript, which does not alter the given arrays.
var coll1 = [{ id: 123, Name: 'Ben', Type: 'Car' }, { id: 124, Name: 'Morgan', Type: 'Van' }, { id: 125, Name: 'Josh', Type: 'Bus' }],
coll2 = [{ id: 123, Name: 'Ben', Type: 'House' }, { id: 124, Name: 'Morgan', Type: 'Flat' }, { id: 126, Name: 'Jack', Type: 'Landrover' }],
hash = Object.create(null),
merged = coll1.map(function (o) {
hash[o.id] = {};
Object.keys(o).forEach(function (k) {
hash[o.id][k] = o[k];
});
return hash[o.id];
});
coll2.forEach(function (o) {
if (hash[o.id]) {
if (o.Type === 'Van' || o.Type === 'Car') {
hash[o.id].Type = o.Type;
}
} else {
hash[o.id] = {};
Object.keys(o).forEach(function (k) {
hash[o.id][k] = o[k];
});
merged.push(hash[o.id]);
}
});
console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can sort the concated list and then process a filtering on the basis of neighborhood comparison :
var list1 = [{ id: 123, Name: 'Ben', Type: 'Car' }, { id: 124, Name: 'Morgan', Type: 'Van' }, { id: 125, Name: 'Josh', Type: 'Bus' }],
list2 = [{ id: 123, Name: 'Ben', Type: 'House' }, { id: 124, Name: 'Morgan', Type: 'Flat' }, { id: 126, Name: 'Jack', Type: 'Landrover' }];
var finalList = list2.concat(list1).sort((a,b) => a.id - b.id).filter((x, i, arr) => {
if (i < arr.length - 1){
if (x.id !== arr[i+1].id || x.Type === "Car" || x.Type === "Van") return true;
}
else if (x.id !== arr[i-1].id || x.Type === "Car" || x.Type === "Van") return true;
});
console.log(finalList);

Categories

Resources