Merge Object Array into Array matched by property value - javascript

I am trying to merge in an array to an existing array by a key (id). Is there any easy way to do this?
For example:
people = [{id: 1, name: 'John Doe'}, {id: 2, name: 'Jane Doe'}];
places = [{id: 1, state: 'CA'}, {id: 2, state: 'AK'}];
// expected output I want is
result = [{id: 1, name: 'John Doe', places: {id: 1, state: 'CA'}}, {id: 2, name: 'Jane Doe', places: {id: 2, state: 'AK}'}}];
How can I get places property id to map into people id so basically the ID's match up and they keys are carried in?

Here is the JS way to implement the scenario :
const people = [{id: 1, name: 'John Doe'}, {id: 2, name: 'Jane Doe'}];
const places = [{id: 1, state: 'CA'}, {id: 2, state: 'AK'}];
const result = people.map(ppl => {
ppl.places = places.find(plc => plc.id === ppl.id)
return ppl;
})
console.log(result)
// ES6 way
let res = people.map(obj => {
let data = places.find(item => item.id === obj.id);
return {...obj, places: data}
});
console.log('ES6 way ......',res)

Related

How to filter array of objects by another array of objects by property using javascript

I have two nested array of objects, how to compare two array of objects by
id from arrobj1 and assignId from arrobj2 using javascript
So, I would to know how to compare array of objects by id and assignId and return array of objects using javascript
Tried
const result = arrobj1.filter(arr1 => {
arrobj2.find(arr2 => arr2.assignId === arr1.id)
});
var arrobj1 =[
{id: 1, name: 'xxx', value:100},
{id: 2, name: 'yyy', value:200},
{id: 3, name: 'zzz', value:400}
]
var arrobj2 =[
{country: 'IN', name: 'lina', assignId:2},
{country: 'MY', name: 'john', assignId:3},
{country: 'SG', name: 'peter', assignId:6}
]
Expected Code:
[
{id: 2, name: 'yyy', value:200},
{id: 3, name: 'zzz', value:400}
]
You have it almost correct, but you need to return in your filter, either by explicitly adding the return keyword or by removing the braces to use the arrow function's implicit return:
const result = arrobj1.filter(arr1 =>
arrobj2.find(arr2 => arr2.assignId === arr1.id)
)
// or
const result = arrobj1.filter(arr1 => {
return arrobj2.find(arr2 => arr2.assignId === arr1.id)
})
We can combine Array.filter() and Array.some() to make it more simple
let result = arrobj1.filter(a1 => arrobj2.some(a2 => a2.assignId === a1.id) )
console.log(result)
For your code,the reason is that you have missing return when invoke find
var arrobj1 =[
{id: 1, name: 'xxx', value:100},
{id: 2, name: 'yyy', value:200},
{id: 3, name: 'zzz', value:400}
]
var arrobj2 =[
{country: 'IN', name: 'lina', assignId:2},
{country: 'MY', name: 'john', assignId:3},
{country: 'SG', name: 'peter', assignId:6}
]
let result = arrobj1.filter(a1 => arrobj2.some(a2 => a2.assignId === a1.id) )
console.log(result)
You can generally go with the filter and some combination as #flyingfox mentioned in the answer, But if you'd have thousands of records then your time complexity would increase which you can solve by removing the nested some loop.
So more performant code would look like the following for a bigger data set.
And yes, Either use return with braces or simply remove the braces for one-liner returns!
var arrobj1 = [
{ id: 1, name: 'xxx', value: 100 },
{ id: 2, name: 'yyy', value: 200 },
{ id: 3, name: 'zzz', value: 400 },
]
var arrobj2 = [
{ country: 'IN', name: 'lina', assignId: 2 },
{ country: 'MY', name: 'john', assignId: 3 },
{ country: 'SG', name: 'peter', assignId: 6 },
]
var obj = {}
for (const elem of arrobj2) {
obj[elem.assignId] = true
}
let result = arrobj1.filter((a1) => obj[a1.id])
console.log(result)

Use lodash groupBy function to categorize objects in an array

i have an array of products that each product has a category object. I need to organize by category and include the category object. GroupBy function include only one parameter.
the array of products
const data = [
{id: 1, 'name': 'produto1', category: {id: 1, name: 'shirts', description: 'super roupa'}},
{id: 2, 'name': 'produto2', category: {id: 1, name: 'shirts', description: 'super roupa'}},
{id: 3, 'name': 'produto3', category: {id: 2, name: 'jackets', description: 'super jackets'}},
{id: 4, 'name': 'produto4', category: {id: 2, name: 'jackets', description: 'super jackets'}},
]
expected result:
[
{
category: {id: 1, name: 'clothes', description: 'super roupa'},
products:[{id:1, name: 'produt1'}, {id: 2, name: 'produto1'} ]
},
{
category: {id: 2, name: 'jackets', description: 'super jackets'},
products:[{id:3, name: 'produt3'}, {id: 4, name: 'produto4'} ]
},
]
Group by the category.id, and then map the each group to an object by taking the category from the 1st item in the group, and omitting category from all products:
const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
const result = _(data)
.groupBy('category.id')
.map(group => ({
category: _.head(group).category,
products: _.map(group, o => _.omit(o, 'category'))
}))
.value()
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
Or the _.flow() function equivalent with lodash/fp:
const { flow, groupBy, map, head, omit } = _
const fn = flow(
groupBy('category.id'),
map(group => ({
category: head(group).category,
products: map(omit('category'), group)
}))
)
const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
const result = fn(data)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
Here's a solution without lodash:
You could reduce the data array. Destructure the parameter to get category and rest of the properties separately. Here rest will have id and name properties. Then create an accumulator object with each unique category's id as key. Set the value to be the final objects needed in the output. If the key already exists, update it's products array. Else, add a new key to the accumulator. Then finally use Object.values() to convert this accumulator object to an array of required values
const data = [{"id":1,"name":"produto1","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":2,"name":"produto2","category":{"id":1,"name":"shirts","description":"super roupa"}},{"id":3,"name":"produto3","category":{"id":2,"name":"jackets","description":"super jackets"}},{"id":4,"name":"produto4","category":{"id":2,"name":"jackets","description":"super jackets"}}]
const merged = data.reduce((acc, { category, ...rest }) => {
acc[category.id] = acc[category.id] || { category, products: [] };
acc[category.id].products.push(rest);
return acc;
}, {})
console.log(Object.values(merged))

Modify object values in an array of objects

I have an array of objects that looks like this:
const arr1 = [
{id: 1, name: 'Dave', tax: 123.34543}
{id: 2, name: 'John', tax: 3243.12323}
{id: 3, name: 'Tom', tax: 122.34324}
]
And I am trying to round off the tax value, so in the end the array should look like this:
[
{id: 1, name: 'Dave', tax: 123.34}
{id: 2, name: 'John', tax: 3243.12}
{id: 3, name: 'Tom', tax: 122.34}
]
I tried using the map function like so:
arr1.map(value => Math.round(value.tax * 100)/100);
but instead of getting a modified array of objects, I get an array with only the result of the Math.round which looks like this:
[ 123.34, 3243.12, 122.34]
How do I map the array of objects to get the expected result as described above.
Thanks.
You can update tax in your map function.
See implementation below.
const arr1 = [
{id: 1, name: 'Dave', tax: '123.34543'},
{id: 2, name: 'John', tax: '3243.12323'},
{id: 3, name: 'Tom', tax: '122.34324'},
];
const taxRoundedArray = arr1.map(item => {
let tax = Math.round(item.tax * 100)/100
return {
...item,
tax
}
});
console.log(taxRoundedArray);
You could map new objects with the wanted values.
const
array = [{ id: 1, name: 'Dave', tax: 123.34543 }, { id: 2, name: 'John', tax: 3243.12323 }, { id: 3, name: 'Tom', tax: 122.34324 }],
result = array.map(o => Object.assign({}, o, { tax: Math.round(o.tax * 100) / 100 }));
console.log(result);
You are very close to the correct solution, see below:
arr1.map(value => {
value.tax = Math.round(value.tax * 100)/100);
return value
});
You need to return the altered object otherwise it gets overwritten.
Hope this helps
Lloyd
Array.map processes the entry in array and return the processed value. In the attempt, you were only returning the updated tax, however, you will need to return the object. Try following
const arr1 = [{id: 1, name: 'Dave', tax: 123.34543},{id: 2, name: 'John', tax: 3243.12323},{id: 3, name: 'Tom', tax: 122.34324}];
const arr2 = arr1.map(({tax, ...rest}) => ({...rest, tax: Math.round(tax * 100)/100}));
console.log(arr2);
map over the array and return each object with a new tax value that has been turned to a floating-point number fixed to two decimal places.
const arr1 = [{"id":1,"name":"Dave","tax":"123.34543"},{"id":2,"name":"John","tax":"3243.12323"},{"id":3,"name":"Tom","tax":"122.34324"}];
const arr2 = arr1.map(obj => {
const tax = +Number.parseFloat(obj.tax).toFixed(2);
return { ...obj, tax };
})
console.log(arr2);
You can do:
const arr1 = [
{id: 1, name: 'Dave', tax: '123.34543'},
{id: 2, name: 'John', tax: '3243.12323'},
{id: 3, name: 'Tom', tax: '122.34324'}
];
const result = arr1.map(user => {
user.tax = (Math.round(+user.tax * 100) / 100);
return user;
});
console.log(result);

JavaScript Update multiple object properties

I have this code below that finds the index of specific object using findIndex method and Update object's name property. Is there anyway i can update mutiple object's name property? E.g.
var rofl = ["0"];
// Instead of ["0"] how do i update multiple object by putting var rofl = ["1","2","3"];
let myArray = [
{id: 0, name: "Jhon"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
],
objIndex = myArray.findIndex((obj => obj.id == rofl));
console.log("Before update: ", myArray[objIndex]) // {id: 0, name: "Jhon"}
myArray[objIndex].name = ("Jerry");
console.log("After update: ", myArray[objIndex]) // {id: 0, name: "Jerry"}
Use forEach instead:
const myArray = [
{id: 0, name: "Jhon"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
];
["1","2","3"].forEach(findId =>
myArray.find(({ id }) => id == findId).name = 'Jerry'
);
console.log(myArray);
If the IDs have a chance of not existing in the array, you'll have to add a test for that as well:
const myArray = [
{id: 0, name: "Jhon"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
];
["1","2","3", "10"].forEach(findId => {
const foundObj = myArray.find(({ id }) => id == findId);
if (foundObj) foundObj.name = 'Jerry';
});
console.log(myArray);
Use Array.forEach
let myArray = [{id: 0, name: "Jhon"},{id: 1, name: "Sara"},{id: 2, name: "Domnic"},{id: 3, name: "Bravo"}];
let rofl = ["1","2","3"];
myArray.forEach((obj) => {if(rofl.includes(obj.id.toString())) obj.name = 'Jerry'})
console.log(myArray);

Omit matched object between Arrays

I'm trying to compare newProp (Array of objects) with prop (Another array of objects), and when there is a match, it will be removed off newProp array.
prop = [{ id: 1, name: 'John Doe}, {id: 2, name: 'Jane Doe'}, {id: 3. name: 'Baby Doe'}]
newProp = [{id: 4, name: 'Johnny Doe' }, {id: 1, name: 'John Doe'} ....]
Here is what I have tried, wonder if there is better / cleaner way of solving this problem.
let prop = [{ id: 1, name: 'John Doe'}, {id: 2, name: 'Jane Doe'}, {id: 3, name: 'Baby Doe'}]
let newProp = [{id: 4, name: 'Johnny Doe' }, {id: 1, name: 'John Doe'}]
prop.map( (i,Iindex) => {
newProp.map((o, oIndex ) => {
if (i.id == o.id) {
prop.splice(Iindex, 1);
console.log(prop);
}
})
})
One way to do it is to filter() out the items you don't need.
It's cleaner and more readable (you'd see it all over the place in code of folks who follow functional programming), however it produces a new array, thus negatively affecting performance if called very frequently on very large input arrays.
newProp = newProp
.filter(newPropElement =>
prop.every(propElement => newPropElement.id !== propElement.id)
)

Categories

Resources