Merge all keys into single object with the same Id in JavaScript - 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

Related

TS/JS, Unable to sum more than one properties, using map set and get

I have been trying to create a summary of an array of objects where it's grouped by the value of one property and 2 or more properties should get summed.
But for some reason the way I am trying is only giving me 2 values the property I am grouping by and first property I am summing.
I am unable to sum the next property.
The array I am starting with
combinedItems
[
{
itemSi: 1,
productId: 'one',
taxableValue: 100,
taxValue: 10,
product: { id: 'one', productName: 'product one', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
},
{
itemSi: 2,
productId: 'two',
taxableValue: 100,
taxValue: 10,
product: { id: 'two', productName: 'product two', taxId: 'one' },
tax: { id: 'one', taxName: 'tax one' }
}
]
I need to be able to group by the taxName and sum the taxableValue and taxValue.
const summaryValues = new Map<any []>();
for(const {tax, taxableValue, taxValue} of combinedItems)
summaryValues.set(
tax.taxName,
(summaryValues.get(tax.taxName) || 0) + taxableValue,
(summaryValues.get(tax.taxName) || 0) + taxValue,
);
const summaries = [...summaryValues]
console.log(summaries);
const taxSummary = summaries.map(x => ({
taxName: x[0],
taxableValue: x[1],
taxValue: x[2]
}));
console.log(taxSummary)
The result I am getting
[ [ 'tax one', 200 ] ]
[ { taxName: 'tax one', taxableValue: 200, taxValue: undefined } ]
This is how the combined items are gotten:
const items: any[] = [
{
itemSi: 1,
productId: "one",
taxableValue: 100,
taxValue: 10
},
{
itemSi: 2,
productId: "two",
taxableValue: 100,
taxValue: 10
}
];
const products: any[] = [
{
id: "one",
productName:"product one",
taxId: "one"
},
{
id: "two",
productName:"product two",
taxId: "one"
}
]
const taxes: any[] = [
{
id: "one",
taxName:"tax one"
},
{
id: "two",
taxName:"tax two"
}
]
let combinedItems: any [] = []
combinedItems = items.map(x => {
let pdtItem = products.find(z => z.id === x.productId);
let taxItem = taxes.find(z => z.id === pdtItem.taxId);
let item = {...x, product: {...pdtItem }, tax: {...taxItem}};
return item;
});
console.log(combinedItems)
Map is a key-value store. What you're trying to do appears to be calling set with three arguments, whereas it only takes two (key and value).
If you need to produce multiple aggregations, you could store the results in an object:
const summaries = new Map();
for (const { tax: { taxName }, taxableValue, taxValue } of combinedItems) {
const currentSummary = summaries.get(taxName) || { taxableValue: 0, taxValue: 0 }
summaries.set(
taxName,
{ taxableValue: currentSummary.taxableValue + taxableValue, taxValue: currentSummary.taxValue + taxValue }
);
}

Compare two objects in an array, delete the duplicate data, and combine the different data?

I am getting a list of objects in an array, some of which are duplicates. However, the condition that produces the duplicates is different.
So picture an array:
var array = [{id: 1, name: 'test', condition: 'left'},
{id: 2, name: 'example', condition: 'left'},
{id: 1, name: 'test', condition: 'right'},
{id: 3, name: 'foobar', condition: 'right'}]
What I am looking for:
var solution = [{id: 1, name: 'test', condition: ['left', 'right']},
{id: 2, name: 'example', condition: 'left'},
{id: 3, name: 'foobar', condition: 'right'}]
I am able to delete duplicates no problem using this method:
var available = result.reduce((unique, o) => {
if (!unique.some((obj) => obj.id === o.id && obj.name === o.name)) {
unique.push(o);
}
return unique;
}, []);
But would Like to combine the condition data
You could collect all with an object with combined keys.
const
array = [{ id: 1, name: 'test', condition: 'left' }, { id: 2, name: 'example', condition: 'left' }, { id: 1, name: 'test', condition: 'right' }, { id: 3, name: 'foobar', condition: 'right' }],
keys = ['id', 'name'],
result = Object.values(array.reduce((r, o) => {
const key = keys.map(k => o[k]).join('|');
if (r[key]) r[key].condition = [].concat(r[key].condition, o.condition);
else r[key] = { ...o };
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a concise solution with 4 steps that only checks for unique IDs:
find the unique IDs
for each unique ID, find the values of that ID
for each group of values with the same ID, find the unique conditions
for each group of values with the same ID, create 1 output value with the unique ID, name, and conditions
let array = [{id: 1, name: 'test', condition: 'left'},
{id: 2, name: 'example', condition: 'left'},
{id: 1, name: 'test', condition: 'right'},
{id: 3, name: 'foobar', condition: 'right'}];
let groupedById = [...new Set(array.map(v => v.id))]
.map(id => {
let valuesWithId = array.filter(v => v.id === id);
let condition = [...new Set(valuesWithId.map(v => v.condition))];
return { ...valuesWithId[0], condition};
});
console.log(groupedById);
If you really have data that has values of the same ID but different names, this can be expanded to:
Iterate the input array, and for each value:
If it has an unseen ID & name combination, add it to the output (after transforming condition to an array).
If it has a seen ID & name combination, add it's condition to its existing counterpart (if it's not present already).
let array = [{id: 1, name: 'test', condition: 'left'},
{id: 2, name: 'example', condition: 'left'},
{id: 1, name: 'test', condition: 'right'},
{id: 3, name: 'foobar', condition: 'right'}];
let groupedByIdAndName = [];
array.forEach(value => {
let duplicate = groupedByIdAndName.find(v => v.id === value.id && v.name === value.name);
if (!duplicate)
groupedByIdAndName.push({...value, condition: [value.condition]});
else if (duplicate.condition.every(c => c !== value.condition))
duplicate.condition.push(value.condition);
});
console.log(groupedByIdAndName);
You can accomplish this in two steps.
Group the data by the id
Merge values for each group by combining the values of their properties
const array = [
{ id: 1 , name: 'test' , condition: 'left' },
{ id: 2 , name: 'example' , condition: 'left' },
{ id: 1 , name: 'test' , condition: 'right' },
{ id: 3 , name: 'foobar' , condition: 'right' }
];
const groupBy = (key, objs) => objs.reduce((acc, obj) =>
({ ...acc, [obj[key]]: [...(acc[obj[key]] || []), obj] }), {});
const combine = (newVal, oldVal) =>
oldVal != null
? Array.isArray(oldVal)
? !oldVal.includes(newVal)
? [ ...oldVal, newVal ]
: oldVal
: oldVal !== newVal
? [ oldVal, newVal ]
: oldVal
: newVal;
const merge = (objs) => objs.reduce((acc, obj) =>
Object.keys(obj).reduce((acc1, key) =>
({ ...acc1, [key]: combine(obj[key], acc1[key]) }), acc), {});
const groupByAndMerge = (key, items) =>
Object.values(groupBy(key, items)).map(merge);
console.log(groupByAndMerge('id', array));
.as-console-wrapper { top: 0; max-height: 100% !important; }
Code golf
I reduced the function to a single-line statement with a size of 259 bytes.
// Size: 259 bytes
f=(k,a)=>Object.values(a.reduce((r,i)=>({...r,[i[k]]:[...(r[i[k]]||[]),i]}),{})).map(g=>g.reduce((s,o)=>Object.keys(o).reduce((t,m)=>({...t,[m]:t[m]!=null?Array.isArray(t[m])?!t[m].includes(o[m])?[...t[m],o[m]]:t[m]:t[m]!==o[m]?[t[m],o[m]]:t[m]:o[m]}),s),{}))
console.log(f('id',[{id:1,name:'test',condition:'left'},{id:2,name:'example',condition:'left'},{id:1,name:'test',condition:'right'},{id:3,name:'foobar',condition:'right'}]));
.as-console-wrapper { top: 0; max-height: 100% !important; }

Pick unique sub-objects from list of objects and transform them with Ramda

With the following data structure...
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
]
I want to pick unique brands... that's easy enough.
const pickBrands = RM.pipe(
RM.map(RM.prop('brand')),
RM.uniqBy(RM.prop('id'))
)
But ultimately, I need to transform a whole thing like this...
const brands = [
{ id: 'A', branches: ['1', '3'] },
{ id: 'B', branches: ['2'] },
]
I am kinda confused how could I approach that considering that after the first map, I am losing information about a branch.
Final solution:
https://runkit.com/fredyc/5d2e1bf1df8aec001aff7f64
This might help too:
const group = R.pipe(
R.groupBy(R.path(['brand', 'id'])),
R.values,
R.map(
R.applySpec({
id: R.path([0, 'brand', 'id']),
branches: R.pluck('id'),
}),
),
);
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
];
console.log('group', group(branches));
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
You can use R.groupBy with R.path to group by brand.id, and then use R.toPairs and R.map with R.zipObject to generate the new object from the groups.
Example (annotated by #ScottSauyet):
const { pipe, groupBy, path, map, pluck, toPairs, zipObj } = R
const fn = pipe(
groupBy(path(['brand', 'id'])), //=> {"A": [{brand: {id: "A"}, id: "1"}, {brand: {id: "A"}, id: "3"}], B: [{brand: {id: "B"}, id: "2"}]}
map(pluck('id')), //=> {A: ["1", "3"], B: ["2"]}
toPairs, //=> [["A", ["1", "3"]], ["B", ["2"]]]
map(zipObj(['id', 'brand']) ) //=> [{id: "A", brand: ["1", "3"]}, {id: "B", brand: ["2"]}]
)
const branches = [
{ id: '1', brand: { id: 'A' } },
{ id: '2', brand: { id: 'B' } },
{ id: '3', brand: { id: 'A' } }
]
const result = fn(branches)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>
Note: My original solution used R.applySpec({ id: head, branches: last }), but it seems that I'm the only one to find it more readable.
You can use plain old JS to achieve your outcome, use reduce with findIndex to check if the id already exists, if it does, push the id to the existing object, otherwise, push the new object:
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
]
console.log(branches.reduce((a, {id, brand}) => {
const i = a.findIndex(o => o.id === brand.id)
i + 1 ? a[i].branches.id.push(id) : a.push({id: brand.id, branches: { id: [id] }})
return a
}, []))
You could take a Map for collecting brands.
const
branches = [{ id: '1', brand: { id: 'A' } }, { id: '2', brand: { id: 'B' } }, { id: '3', brand: { id: 'A' } }],
brands = Array.from(
branches.reduce((m, { id: branche, brand: { id } }) =>
m.set(id, [...(m.get(id) || []), branche]), new Map),
([id, branches]) => ({ id, branches: { id: branches }})
);
console.log(brands);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a solution using values and reduceBy.
First let's define an empty template for brands:
const brandTmpl =
{ id: null,
branches: [] };
Then let's define a function that returns the brand id for a given branch:
const brandId = path(['brand', 'id']);
brandId({ id: '1', brand: { id: 'A' }});
//=> 'A'
Then given a brand and a branch, let's define a function that "adds" a branch to a brand:
const brand = (brd, bch) => (
{ id: brandId(bch),
branches: append(bch.id, brd.branches) });
brand(brandTmpl, { id: '1', brand: { id: 'A' }});
//=> {id: 'A', branches: ['1']}
Now let's use all of that to merge branches by brand:
const brands = reduceBy(brand, brandTmpl, brandId);
brands([
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}]);
//=> { A: { id: "A", branches: ["1", "3"]},
//=> B: { id: "B", branches: ["2"]} }
Finally we can simply extract the values:
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }} ];
const brandId = path(['brand', 'id']);
const brandTmpl =
{ id: null,
branches: [] };
const brand = (brd, bch) => (
{ id: brandId(bch),
branches: append(bch.id, brd.branches) });
const brands = reduceBy(brand, brandTmpl, brandId);
const pickBrands = compose(values, brands);
console.log(
pickBrands(branches)
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.min.js"></script>
<script>const {path, append, reduceBy, compose, values} = R;</script>
try this:
const branches = [
{ id: '1', brand: { id: 'A' }},
{ id: '2', brand: { id: 'B' }},
{ id: '3', brand: { id: 'A' }}
]
const groupBy = (branches) => branches.reduce((acc, ele)=>( (acc[ele.brand.id] = acc[ele.brand.id] || []).push(ele), acc),{})
const reformat = ([k, v]) =>({id: k, branches: {id:v.map(({id})=>id)}})
const result = Object.entries(groupBy(branches)).map(ele => reformat(ele))
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);

Merging/extend javascript object arrays based on join of a key property in each

I am wanting to merge the following object arrays, by first joining on the id property
var arr1 = [{
id: 1,
name: 'fred',
title: 'boss'
},{
id: 2,
name: 'jim',
title: 'nobody'
},{
id: 3,
name: 'bob',
title: 'dancer'
}];
var arr2 = [{
id: 1,
wage: '300',
rate: 'day'
},{
id: 2,
wage: '10',
rate: 'hour'
},{
id: 3,
wage: '500',
rate: 'week'
}];
So the result would be
[{
id: 1,
name: 'fred',
title: 'boss',
wage: '300',
rate: 'day'
},{
id: 2,
name: 'jim',
title: 'nobody',
wage: '10',
rate: 'hour'
},{
id: 3,
name: 'bob',
title: 'dancer',
wage: '500',
rate: 'week'
}]
I would like to avoid using js frameworks (if possible), although ExtJs is already part of the project.
AT the moment I have a loop with an inner loop that if the keys match it copies the properties and breaks out of the inner loop to start the next outer loop.
Any better suggestions?
Like this?
var combined = [];
function findSecond(id,second){
for (var i=0;i<second.length;i++){
if(second[i].id === id){
return second[i];
}
}
return null
}
while (el = arr1.pop()){
var getSec = findSecond(el.id,arr2);
if (getSec){
for (var l in getSec){
if (!(l in el)) {
el[l] = getSec[l];
}
}
combined.push(el);
}
}
If the arrays have the same length, and the id's are equal, a simpler merge will do:
function merge(a1,a2) {
var i = -1;
while ((i = i+1)<a1.length) {
for (var l in a2[i]) {
if (!(l in a1[i] )) {
a1[i][l] = a2[i][l];
}
}
}
return a1;
}
Here's a working example
[Edit 2016/07/30] Added a snippet using more functional approach and, based on #djangos comment, an extra method to combine both arrays.
(function() {
var alert = function(str) {document.querySelector('#result').textContent += str + '\n';};
var arrays = getArrays();
alert('Combine on id (shared id\'s):')
alert(JSON.stringify(combineById(arrays.arr1, arrays.arr2), null, ' '));
alert('\nCombine on id (all id\'s):')
alert(JSON.stringify(combineBothById(arrays.arr1, arrays.arr2), null, ' '));
// for combineBothById the parameter order isn't relevant
alert('\nCombine on id (all id\'s, demo parameter order not relevant):')
alert(JSON.stringify(combineBothById(arrays.arr2, arrays.arr1), null, ' '));
// combine first array with second on common id's
function combineById(arr1, arr2) {
return arr1.map(
function (el) {
var findInB = this.filter(function (x) {return x.id === el.id;});
if (findInB.length) {
var current = findInB[0];
for (var l in current) {
if (!el[l]) {el[l] = current[l];}
}
}
return el;
}, arr2);
}
// combine first array with second on all id's
function combineBothById(arr1, arr2) {
var combined = arr1.map(
function (el) {
var findInB = this.filter(function (x) {return x.id === el.id;});
if (findInB.length) {
var current = findInB[0];
for (var l in current) {
if (!el[l]) {el[l] = current[l];}
}
}
return el;
}, arr2);
combined = combined.concat(arr2.filter(
function (el) {
return !this.filter(function (x) {return x.id === el.id;}).length;
}, combined));
return combined;
}
function getArrays() {
return {
arr1: [{
id: 1,
name: 'fred',
title: 'boss'
}, {
id: 2,
name: 'jim',
title: 'nobody'
}, {
id: 3,
name: 'bob',
title: 'dancer'
}],
arr2: [{
id: 1,
wage: '300',
rate: 'day'
}, {
id: 2,
wage: '10',
rate: 'hour'
}, {
id: 4,
wage: '500',
rate: 'week'
}]
};
}
}());
<pre id="result"></pre>
You can merge two arrays by id column with Alasql library:
var res = alasql('SELECT * FROM ? arr1 JOIN ? arr2 USING id', [arr1,arr2]);
Try this example at jsFiddle.
try this...
var arr1 = [{
id: 1,
name: 'fred',
title: 'boss'
},{
id: 2,
name: 'jim',
title: 'nobody'
},{
id: 3,
name: 'bob',
title: 'dancer'
}];
var arr2 = [{
id: 1,
wage: '300',
rate: 'day'
},{
id: 2,
wage: '10',
rate: 'hour'
},{
id: 3,
wage: '500',
rate: 'week'
}];
let arr5 = arr1.map((item, i) => Object.assign({}, item, arr2[i]));
console.log(arr5)

Categories

Resources