How to first combine properties of an object then remove the duplicates in an array of objects using Javascript - javascript

I have an array of objects here:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
I want to add quantities of the duplicate objects together before removing them
So the result is:
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test3", quantity:2 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:2 },
{ id: 6, name: "test8", quantity:1 }
];
I have seen variations of it done removing duplicates using map or reduce but I haven't seen anything that can what I want to accomplish in an eloquent way without using too many loops.
I have been thinking about how to best accomplish this all day and haven't found anything, any help would be appreciated

You can use reduce with an object to store the element with each id.
const arr = [
{ id: 1, name: "test1", quantity:1 },
{ id: 2, name: "test2", quantity:1 },
{ id: 2, name: "test3", quantity:1 },
{ id: 3, name: "test4", quantity:1 },
{ id: 4, name: "test5", quantity:1 },
{ id: 5, name: "test6", quantity:1 },
{ id: 5, name: "test7", quantity:1 },
{ id: 6, name: "test8", quantity:1 }
];
const res = Object.values(
arr.reduce((acc,curr)=>{
acc[curr.id] = acc[curr.id] || {...curr, quantity: 0};
acc[curr.id].quantity += curr.quantity;
return acc;
}, {})
);
console.log(res);

const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 }
];
var result = arr.reduce(function (r, a) {
r[a.id] = r[a.id] || { id: a.id, quantity: 0, name: a.name };
r[a.id].quantity += a.quantity;
return r;
}, Object.create(null));
console.log(JSON.stringify(result));

Using forEach loop and build object with aggregated quantity count.
const convert = (arr) => {
const res = {};
arr.forEach(({ id, ...rest }) =>
res[id] ? (res[id].quantity += 1) : (res[id] = { id, ...rest })
);
return Object.values(res);
};
const arr = [
{ id: 1, name: "test1", quantity: 1 },
{ id: 2, name: "test2", quantity: 1 },
{ id: 2, name: "test3", quantity: 1 },
{ id: 3, name: "test4", quantity: 1 },
{ id: 4, name: "test5", quantity: 1 },
{ id: 5, name: "test6", quantity: 1 },
{ id: 5, name: "test7", quantity: 1 },
{ id: 6, name: "test8", quantity: 1 },
];
console.log(convert(arr));

Related

How to get values of child objects in an array of objects in javascript

states = [{
name: telangana,
cities: [{
id: 1,
name: foo
}, {
id: 2,
name: joo
}, {
id: 3,
name: goo
}]
},
{
name: punjab,
cities: [{
id: 4,
name: tyu
}, {
id: 5,
name: ery
}, {
id: 6,
name: doo
}]
},
{
name: mumbai,
cities: [{
id: 7,
name: eee
}, {
id: 8,
name: qqq
}, {
id: 9,
name: www
}]
},
]
I want response like [foo, joo, goo, tyu, ery,doo, eee,qqq,www]
Can someone help me ?
Just write one line:
Learn more about reduce() and map()
const states = [{ name: "telangana", cities: [{ id: 1, name: "foo" }, { id: 2, name: "joo" }, { id: 3, name: "goo" }] }, { name: "punjab", cities: [{ id: 4, name: "tyu" }, { id: 5, name: "ery" }, { id: 6, name: "doo" }] }, { name: "mumbai", cities: [{ id: 7, name: "eee" }, { id: 8, name: "qqq" }, { id: 9, name: "www" }] }, ];
const result = states.reduce((acc, { cities }) => [...acc, ...cities.map(({ name }) => name)], []);
console.log(result);
const getNames = (data) => {
const nameArr = [];
data.forEach((ele) => {
ele.cities.forEach((ele2) => {
nameArr.push(ele2.name);
})
})
return nameArr;
}
getNames(states);
Try this please!
states = [{
name: "telangana",
cities: [{
id: 1,
name: "foo"
}, {
id: 2,
name: "joo"
}, {
id: 3,
name: "goo"
}]
},
{
name: "punjab",
cities: [{
id: 4,
name: "tyu"
}, {
id: 5,
name: "ery"
}, {
id: 6,
name: "doo"
}]
},
{
name: "mumbai",
cities: [{
id: 7,
name: "eee"
}, {
id: 8,
name: "qqq"
}, {
id: 9,
name: "www"
}]
},
]
const wantedArray = []
for(i=0; i < states.length; i++){
for(j=0; j < states[i].cities.length; j++){
wantedArray.push(states[i].cities[j].name)
}
}
console.log(wantedArray)
Just give it an empty array, then you loop through the states indexes, each index in states will have a cities array, then you just need to loop it again in that array to get each name of the cities. From then, you are using the push method that Javascript provides to push it to the empty array.
Here's how I'm doing it in JSFiddle, there will have a better way to do this, too.

Question from a beginner: Unexpected JS behavior [duplicate]

I'm trying to convert an array of objects where i return duplicated objects if the object properties quantity is greater than 1.
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
// desired return
[
{ id: 1, name: "Scissor", price: 2 }
{ id: 1, name: "Scissor", price: 2 }
{ id: 1, name: "Scissor", price: 2 }
{ id: 2, name: "Hat", price: 6.5}
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
{ id: 3, name: "Socks", price: 0.5 }
]
My code:
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
let newObjects= [];
Object.entries(objects).forEach(([key, value]) => {
for (let i=0; i < value.quantity; i++){
newObjects.push({ id: value.id, name: value.name, price: value.price})
}
});
console.log(newObjects);
So my code above does work, does return what i wanted, however i feel like there is a better/smoother and more of ES6 and beyond method. Could anyone please suggest a better way?
You could use .fill() and .flatMap().
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
let newObjects = objects.flatMap(e=>
Array(e.quantity).fill({id: e.id, name: e.name, price: e.price})
);
console.log(newObjects);
You can use an array reduce along with an array fill.
The map is required only if you want to have unique references otherwise you can fill using the same object.
const objects = [
{ id: 1, name: "Scissor", price: 2, quantity: 3 },
{ id: 2, name: "Hat", price: 6.5, quantity: 1 },
{ id: 3, name: "Socks", price: 0.5, quantity: 5 },
];
const output = objects.reduce((a, c) => {
return a.concat(Array(c.quantity).fill({}).map(x=>({
id: c.id,
name: c.name,
price: c.price
})))
}, []);
console.log(output)

Assign new properties to an array of Objects

I have an array of Objects
const options = [
{ id: 1, name: "Back Pain" },
{ id: 2, name: "Body aches" },
{ id: 3, name: "Cold Sores" },
{ id: 4, name: "Cough" },
{ id: 5, name: "Constipation" },
];
I am trying to write a function that will assign new properties to the object.
The output I am looking for is:
const options = [
{ value: 1, label: "Back Pain" },
{ value: 2, label: "Body aches" },
{ value: 3, label: "Cold Sores" },
{ value: 4, label: "Cough" },
{ value: 5, label: "Constipation" },
];
I have tried to loop through the array using a for loop, but can not figure it out.
Thanks for the help:)
You can do it like this:
const data=[{ id: 1, name: "Back Pain" },
{ id: 2, name: "Body aches" },
{ id: 3, name: "Cold Sores" },
{ id: 4, name: "Cough" },
{ id: 5, name: "Constipation" },
];
var result = data.map(({id:value, name:label})=>({value, label}));
console.log(result);

Join two objects just like SQL inner join

I have two objects like:
countries = [
{ id: 1, name: 'India', image: 'thumb15.jpg' },
{ id: 2, name: 'Africa', image: 'thumb11.jpg' },
{ id: 3, name: 'Kenya', image: 'thumb10.jpg' }
];
cities = [
{ id: 1, name: 'Ahmedabad', country_id: 1 },
{ id: 2, name: 'Vadodara', country_id: 1 },
{ id: 3, name: 'Cairo', country_id: 2 },
{ id: 4, name: 'Kinshasa', country_id: 2 },
{ id: 5, name: 'Luanda', country_id: 2 },
{ id: 6, name: 'Nairobi', country_id: 3 },
{ id: 7, name: 'Nakuru', country_id: 3 },
{ id: 8, name: 'Mombasa', country_id: 3 },
];
I want to combine these two Objects, just like SQL have INNER JOIN
for example, I want to perform below operation (query) on the above two objects,
SELECT * from countries INNER JOIN cities ON cities.country_id = countries.id
and my expected output will look like:
expected_result = [
{ id: 1, name: "Ahmedabad", country_id: 1, country_name: "India", country_image: "thumb15.jpg" },
{ id: 2, name: "Vadodara", country_id: 1, country_name: "India", country_image: "thumb15.jpg" },
{ id: 3, name: "Cairo", country_id: 2, country_name: "Africa", country_image: "thumb11.jpg" },
{ id: 4, name: "Kinshasa", country_id: 2, country_name: "Africa", country_image: "thumb11.jpg" },
{ id: 5, name: "Luanda", country_id: 2, country_name: "Africa", country_image: "thumb11.jpg" },
{ id: 6, name: "Nairobi", country_id: 3, country_name: "Kenya", country_image: "thumb10.jpg" },
{ id: 7, name: "Nakuru", country_id: 3, country_name: "Kenya", country_image: "thumb10.jpg" },
{ id: 8, name: "Mombasa", country_id: 3, country_name: "Kenya", country_image: "thumb10.jpg" }
];
Thanks in advance.
It is possible to use map function and Map collection to get desired country:
const uniqueCountries = new Map(countries.map(s => [s.id, s]));
const result = cities.map(s => ({ ...s,
country_name: uniqueCountries.get(s.country_id).name }));
An example:
let countries = [
{ id: 1, name: 'India', image: 'thumb15.jpg' },
{ id: 2, name: 'Africa', image: 'thumb11.jpg' },
{ id: 3, name: 'Kenya', image: 'thumb10.jpg' }
];
let cities = [
{ id: 1, name: 'Ahmedabad', country_id: 1 },
{ id: 2, name: 'Vadodara', country_id: 1 },
{ id: 3, name: 'Cairo', country_id: 2 },
{ id: 4, name: 'Kinshasa', country_id: 2 },
{ id: 5, name: 'Luanda', country_id: 2 },
{ id: 6, name: 'Nairobi', country_id: 3 },
{ id: 7, name: 'Nakuru', country_id: 3 },
{ id: 8, name: 'Mombasa', country_id: 3 },
];
const uniqueCountries = new Map(countries.map(s => [s.id, s]));
const result = cities.map(s => ({ ...s,
country_name: uniqueCountries.get(s.country_id).name }));
console.log(result);
UPDATE:
map method creates new array from the calling array. In addition, you can add new properties to your object you want:
let countries = [
{ id: 1, name: 'India', image: 'thumb15.jpg' },
{ id: 2, name: 'Africa', image: 'thumb11.jpg' },
{ id: 3, name: 'Kenya', image: 'thumb10.jpg' }
];
const countriesWithShortCountryNames = countries.map(s=> ({...s,
shortName: s.name.substring(0, 3)}))
console.log(countriesWithShortCountryNames)
Map collection:
The Map object holds key-value pairs and remembers the original
insertion order of the keys.
You could take a hash table for all items of countries, where id is the key and the value is a new object in the wanted format.
{
1: {
country_name: "India",
image: "thumb15.jpg"
},
2: {
country_name: "Africa",
image: "thumb11.jpg"
},
3: {
country_name: "Kenya",
image: "thumb10.jpg"
}
}
Then map a new objects with the original key/value and new properties from the hash table.
Methods used, in order of appearance:
Array#reduce
destructuring assignment with assigning to new variable name
Array#map
var countries = [{ id: 1, name: 'India', image: 'thumb15.jpg' }, { id: 2, name: 'Africa', image: 'thumb11.jpg' }, { id: 3, name: 'Kenya', image: 'thumb10.jpg' }],
cities = [{ id: 1, name: 'Ahmedabad', country_id: 1 }, { id: 2, name: 'Vadodara', country_id: 1 }, { id: 3, name: 'Cairo', country_id: 2 }, { id: 4, name: 'Kinshasa', country_id: 2 }, { id: 5, name: 'Luanda', country_id: 2 }, { id: 6, name: 'Nairobi', country_id: 3 }, { id: 7, name: 'Nakuru', country_id: 3 }, { id: 8, name: 'Mombasa', country_id: 3 }],
countriesH = countries.reduce((r, { id, name: country_name, ...o }) =>
(r[id] = { country_name, ...o }, r), {}),
result = cities.map(o => ({ ...o, ...countriesH[o.country_id] }));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I wrote a library (which emulates dotnet's linq) which makes this a breeze:
import { blinq } from "blinq";
//...
const joinedData = blinq(countries)
.join(
cities,
co => co.id,
ci => ci.country_id,
(country, city) => ({ country, city })
)
.toArray();
const {
blinq
} = window.blinq;
const countries = [{
id: 1,
name: "India",
image: "thumb15.jpg"
},
{
id: 2,
name: "Africa",
image: "thumb11.jpg"
},
{
id: 3,
name: "Kenya",
image: "thumb10.jpg"
}
];
const cities = [{
id: 1,
name: "Ahmedabad",
country_id: 1
},
{
id: 2,
name: "Vadodara",
country_id: 1
},
{
id: 3,
name: "Cairo",
country_id: 2
},
{
id: 4,
name: "Kinshasa",
country_id: 2
},
{
id: 5,
name: "Luanda",
country_id: 2
},
{
id: 6,
name: "Nairobi",
country_id: 3
},
{
id: 7,
name: "Nakuru",
country_id: 3
},
{
id: 8,
name: "Mombasa",
country_id: 3
}
];
const joinedData = blinq(countries)
.join(
cities,
co => co.id,
ci => ci.country_id,
(country, city) => ({
country,
city
})
)
.toArray();
console.log(JSON.stringify(joinedData, null, 2))
<script src="https://cdn.jsdelivr.net/npm/blinq"></script>

Remove first matching item in a collection

Given a collection, how can I remove only the first item that matches a condition?
For example, given this collection:
[
{ id: 1, name: "don" },
{ id: 2, name: "don" },
{ id: 3, name: "james" },
{ id: 4, name: "james" }
]
Filter out the first result that matches { name: "james" }.
Result:
[
{ id: 1, name: "don" },
{ id: 2, name: "don" },
{ id: 4, name: "james" }
]
Using underscore.js _.without and _.findWhere
var myarray = [
{ id: 1, name: "don" },
{ id: 2, name: "don" },
{ id: 3, name: "james" },
{ id: 4, name: "james" }
];
var arr = _.without(myarray, _.findWhere(myarray, {
name: "james"
}));
console.log(arr);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
Using Lodash _.without and _.find
var myarray = [
{ id: 1, name: "don" },
{ id: 2, name: "don" },
{ id: 3, name: "james" },
{ id: 4, name: "james" }
];
var result =_.without(myarray, _.find(myarray, { name: "james" }));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Are you are looking a solution like this?
Iterate and update an array using Array.prototype.splice.
var arr = [
{ id: 1, name: "don" },
{ id: 2, name: "don" },
{ id: 3, name: "james" },
{ id: 4, name: "james" }
];
// loop and remove the first match from the above array
for (i = 0; i < arr.length; i++) {
if (arr[i].name == "james"){
arr.splice(i, 1);
break;
}
}
// write into the browser console
console.log(arr);
with Lodash
var newArray = _.without(array, _.find(array, { name: "james" }));

Categories