const App = () => {
const course = [{
id: 1,
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
}
]
},
{
name: 'Node.js',
id: 2,
parts: [
{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
I am trying to calculate the sum of the exercises in each of the courses so I can get something at the end of each course which says Total exercises: 31 at the end of Half Stack Application Development and total exercises 10: at the end of Node.Js
I have tried
const totals = course.map(c => c.parts.map(c => c.exercises.map(c => c.reduce((a, b) => a + b, 0))))
but received c.exercises.map is not a function.
How could I calculate the sum of each of c.exercises?
exercises looks like this in the console:
(2) [Array(3), Array(2)]
0: (3) [10, 7, 14]
1: (2) [3, 7]
length: 2
This to calculate just the number of exercises per course
const calculateTotalExercises = course =>
course.map(c => c.parts.reduce((res, {
exercises
}) => res + exercises, 0))
const course = [{
id: 1,
name: 'Half Stack application development',
parts: [{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
}
]
},
{
name: 'Node.js',
id: 2,
parts: [{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
console.log(calculateTotalExercises(course))
Probably it will be more convenient to add the total of the exercise to the array like this
const calculateTotalExercises = course =>
course.map(c => ({...c, totalExercise : c.parts.reduce((res, p) => res + p.exercises, 0)}))
const course = [{
id: 1,
name: 'Half Stack application development',
parts: [{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
}
]
},
{
name: 'Node.js',
id: 2,
parts: [{
name: 'Routing',
exercises: 3,
id: 1
},
{
name: 'Middlewares',
exercises: 7,
id: 2
}
]
}
]
console.log(calculateTotalExercises(course))
You could start by breaking the problem down. Here's how I solved this.
I created a function that finds the total number of exercises for one course
let totalExerciseForOneCourse = (parts) => {
return parts.reduce((prev, curr) => prev + curr.exercises, 0)
}
Then we use the map method to go through each course in the courses array returning a new array of objects with everything that was in the courses array and adding in a totalExercises object property
let newCourses = courses.map((course) => {
const total = totalExerciseForOneCourse(course.parts);
return Object.assign({}, course, {
totalExercises: total
})
})
Our totalExerciseForOneCourse function takes an array parameter and calculates the sum of all exercises for one course using the array.reduce method
newCourses contains our new array with all previous and new information
JSFiddle -
https://jsfiddle.net/swish933/9fwzysxa/
The sum of multiple arrays can be rendered in a single component looking like this
{c.parts.reduce((a, b) => a += b.exercises, 0)}
You can just do
let total = 0
courses.map(course => course.parts.map(part => total += part.exercises)
Edit:
Just in case you need to use reduce:
const total = courses.map(course => course.parts.reduce(e1,e2 => e1+e2 ))
Related
im having real trouble to complete an FullStackOpen exersice, it requires to render some data to the page. Give the next code, i have to render the number of Parts that each Course has, and also so reduce the number of Parts/Exersices to render the total of exersices por each Course.
I am not being able to reach the inside of the Parts array of objects
{
name: "Half Stack application development",
id: 1,
parts: [
{
name: "Fundamentals of React",
exercises: 10,
id: 1,
},
{
name: "Using props to pass data",
exercises: 7,
id: 2,
},
{
name: "State of a component",
exercises: 14,
id: 3,
},
{
name: "Redux",
exercises: 11,
id: 4,
},
],
},
{
name: "Node.js",
id: 2,
parts: [
{
name: "Routing",
exercises: 3,
id: 1,
},
{
name: "Middlewares",
exercises: 7,
id: 2,
},
],
},
];```
It's not that difficult, for each element of the array:
number of parts is currentElement.parts.length
number of exercises can be computed using Array.reduce
const data = [
{
name: "Half Stack application development",
id: 1,
parts: [{
name: "Fundamentals of React",
exercises: 10,
id: 1,
},
{
name: "Using props to pass data",
exercises: 7,
id: 2,
},
{
name: "State of a component",
exercises: 14,
id: 3,
},
{
name: "Redux",
exercises: 11,
id: 4,
},
],
},
{
name: "Node.js",
id: 2,
parts: [{
name: "Routing",
exercises: 3,
id: 1,
},
{
name: "Middlewares",
exercises: 7,
id: 2,
},
],
},
];
const res = []
for (const course of data) {
const tmpObj = {
courseName: course.name,
parts: course.parts.length,
exercises: course.parts.reduce((a,b) => a + b.exercises, 0)
}
res.push(tmpObj)
}
console.log(res)
If you want a total number of exercises per course, you will need to reduce each by name; and for each list of parts, reduce by the exercise count.
const main = () => {
const courseData = courses.map(({ name, parts }) => ({
name,
parts: parts.length,
exercises: parts.reduce((sum, { exercises }) => sum + exercises, 0)
}));
console.log(courseData);
};
const courses = [{
name: "Half Stack application development",
id: 1,
parts: [
{ name: "Fundamentals of React" , exercises: 10 , id: 1 },
{ name: "Using props to pass data" , exercises: 7 , id: 2 },
{ name: "State of a component" , exercises: 14 , id: 3 },
{ name: "Redux" , exercises: 11 , id: 4 }
],
}, {
name: "Node.js",
id: 2,
parts: [
{ name: "Routing" , exercises: 3 , id: 1 },
{ name: "Middlewares" , exercises: 7 , id: 2 }
],
}];
main();
.as-console-wrapper { top: 0; max-height: 100% !important; }
I have the following arrays of objects, for example:
const data = [
{
date: '01-01',
products: [
{
id: 1,
value: 6,
label: 'Product 1'
},
{
id: 2,
value: 3,
label: 'Product 2'
}
]
},
{
date: '02-01',
products: [
{
id: 1,
value: 4,
label: 'Product 1'
},
]
},
{
date: '03-01',
products: [
{
id: 1,
value: 11,
label: 'Product 1'
},
{
id: 2,
value: 15,
label: 'Product 2'
}
]
}
]
Then I do the grouping and get the following result:
const output = [
{
id: 1,
name: 'Product 1',
data: [6, 4, 11]
},
{
id: 2,
name: 'Product 2',
data: [3, 15]
}
]
The problem with the solution is that I cannot take into account the missing value (the object with the date "02-01" does not have an object with id: 2). I need to check that the object does not exist and substitute zero instead of the missing value. Maybe you know how to do it?
Solution code below:
const result = data.map(e => e.products).flat().reduce((acc, product) => {
const index = acc.findIndex(item => item.id === product.id);
if(index === -1) {
acc.push({
id: product.id,
name: product.label,
data: [product.value]
})
return acc;
}
const findIndex = acc[index].data.findIndex((innerNode) => innerNode.id === product.id);
if (findIndex === -1) {
console.log(product.value)
acc[index].data.push(product.value);
return acc;
}
return acc;
}, []);
Expected result:
const output = [
{
id: 1,
name: 'Product 1',
data: [6, 4, 11]
},
{
id: 2,
name: 'Product 2',
data: [3, 0, 15]
}
]
You can do this in three passes:
first, you find all dates. When you first encounter a product, you will set all its values to 0 for each of those dates.
then, you iterate products and ensure that, for each date, they have a value - which will be zero by default.
finally, you format the output.
const data = [
{
date: '01-01',
products: [
{
id: 1,
value: 6,
label: 'Product 1'
},
{
id: 2,
value: 3,
label: 'Product 2'
}
]
},
{
date: '02-01',
products: [
{
id: 1,
value: 4,
label: 'Product 1'
},
]
},
{
date: '03-01',
products: [
{
id: 1,
value: 11,
label: 'Product 1'
},
{
id: 2,
value: 15,
label: 'Product 2'
}
]
}
]
// goal is to fill this for each product
let dateToValues = data.map(d => [d.date, 0]);
// build map of product-id to values-for-each-date
let products = new Map();
data.forEach(d => d.products.forEach(p => {
let values = products.get(p.id)?.data;
if (values === undefined) {
values = new Map(dateToValues); // a copy
products.set(p.id, {label: p.label, data: values});
}
values.set(d.date, p.value);
}))
// generate output, skipping dates and only showing their values
let output = [];
products.forEach((v, id) => output.push({
id: id, name: v.label, data: [... v.data.values()]}));
console.log(output)
This question already has answers here:
Destructuring array of objects in es6
(5 answers)
Closed 1 year ago.
I'm wondering if I can destructure this array of objects
const course = {
id: 1,
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
},
]
}
and save the property exercises in a variable, I dont know if we would ever do this, just want to know how and if we can destructure object properties in an array of objects
#ggrlen Here's the array
const arr = [{
name: 'State of a component',
exercises: 14,
id: 3
}];
I want to destruct the object in this array, to extract value of exercises property into a variable, thanks for the reply btw.
Converting my comments into an answer to illustrate various destructuring patterns:
const course = {
id: 1,
name: 'Half Stack application development',
parts: [
{
name: 'Fundamentals of React',
exercises: 10,
id: 1
},
{
name: 'Using props to pass data',
exercises: 7,
id: 2
},
{
name: 'State of a component',
exercises: 14,
id: 3
},
]
};
console.log(course.parts.map(e => e.exercises));
console.log(course.parts.map(({exercises: e}) => e)); // rename to `e`
let {parts: [{exercises}]} = course; // extract nested property
console.log(exercises); // 10
({parts: [,{exercises}]} = course); // second elem
console.log(exercises); // 7
({parts: [,,{exercises}]} = course); // third elem
console.log(exercises); // 14
const arr = [
{
name: 'State of a component',
exercises: 14,
id: 3
},
{
name: 'State of a component',
exercises: 1422,
id: 3
}
];
const [{exercises}] = arr;
console.log(exercises); // 14
let [, ...rest] = arr; // extract everything after the first
console.log(rest);
// from second elem, extract `exercises` as `ex`,
// extract object properties other than `exercises` as `others`
const [,{exercises: ex, ...others}] = arr;
console.log(ex); // 1422
console.log(others);
Yes I am aware of similar questions but it doesn't quite cover my use case here.
I'm having trouble finding a way to bring the time complexity of this down
I have two objects like so
const people = [
{
name: 'Steve',
id: 1,
fruitInBasket: 6
},
{
name: 'James',
id: 2,
fruitInBasket: 4
}
]
const homes = [
{
id: 1,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
},
{
id: 2,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
}
]
so one is a collection of people with a count of fruit in a basket and the other is a collection of homes and within each home is the same users as in the people collection.
Now I want to order the users in each home based on the count of fruitInBasket so I have done this
// create an empty table to store the order of the people
let orderTable = {};
// order the people based off the count in fruitInBasket using lodash orderBy
people = orderBy(people, ['fruitInBasket'], ['desc']);
// create the table
orderTable = people.reduce((acc, item, index) => {
return {
...acc,
[item.id]: index
}
}, {});
// order the people in each home based on the order in the `orderTable`
homes.forEach((home) => {
let members = [];
home.familyMembers.forEach((member) => {
let i = orderTable[member.id];
members[i] = member;
});
home.familyMembers = members;
})
so immediately you can see a nested for loop - which is never ideal.. but I can't figure out a way around this. This method has to sort through quite a lot of data and I am noticing huge performance issues.
Any help would be appreciated!
This should be O(N log N). Its performance bottleneck is the one time sort. Everything else is just O(N) iteration. Some microoptimizations still possible.
Generate an ordered map lookup table.
Just move arrays based on that mapping.
There is a hpc sort library that is measured around 10-40x faster than built-in JavaScript on benchmarks that can be added to increase performance.
I'm not sure, but is the familyMember table the same for every home object? Can you not just copy the same familyMember array to every object or do they have different properties?
Extra optimization per home could be to convert above table to index to index mapping, so that native level array indexing will be used for subsequent ordering.
const orderMap = Object.fromEntries(people.sort((x,y)=>x.fruitInBasket-y.fruitInBasket).map(({id},i)=>[id,i]))
// O(N)+O(NlogN)
homes.forEach(home=>{
const {familyMembers:fms} = home
const arr = new Array(fms.length)
//may want to prefill to maintain PACKED array: https://v8.dev/blog/elements-kinds#avoid-creating-holes
for(const fm of fms) arr[ orderMap[fm.id] ] = fm
home.familyMembers = arr
})
// map lookup O(N)
console.log(homes)
<script>
const people = [
{
name: 'Steve',
id: 1,
fruitInBasket: 6
},
{
name: 'James',
id: 2,
fruitInBasket: 9
}
]
const homes = [
{
id: 1,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
},
{
id: 2,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
}
]
</script>
You can filter and sort:
const people = [
{
name: 'Steve',
id: 1,
fruitInBasket: 6
},
{
name: 'James',
id: 2,
fruitInBasket: 4
},
{
name: 'Cesar',
id: 3,
fruitInBasket: 14
}
]
const homes = [
{
id: 1,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Cesar',
id: 3
},
{
name: 'Steve',
id: 1
}
]
},
{
id: 2,
familyMembers: [
{
name: 'James',
id: 2
},
{
name: 'Steve',
id: 1
}
]
}
]
homes.forEach(function(home){
home.familyMembers.sort((a,b)=>people.find(x=>x.id == a.id).fruitInBasket - people.find(x=>x.id == b.id).fruitInBasket)
})
console.log(homes)
Explanations:
You will iterate through homes:
homes.forEach(function(home){
You will sort the members:
.familyMembers.sort((a,b)
To sort, you have to get the fruits of the members, so you find the correct ID then take the correct property:
people.find(x=>x.id == a.id).fruitInBasket
Then you compare:
(a,b)=>people.find(x=>x.id == a.id).fruitInBasket - people.find(x=>x.id == b.id).fruitInBasket
If what you're looking for is performance, you should change people strucutre:
const people = {
1: {
name: 'Steve',
fruitInBasket: 6
},
2: {
name: 'James',
fruitInBasket: 4
}
}
This way you can retrieve fruits more easily:
people[id].fruits
Also, if your "id" is defined somewhere, don't define it in another place. Your homes should look like this:
const homes = {
1: {
familyMembers: [1, 2, 3]
},
2: {
familyMembers: [1,2]
}
}
So your algorithm goes like this:
const people = {
1: {
name: 'Steve',
fruitInBasket: 6
},
3: {
name: 'James',
fruitInBasket: 4
},
2: {
name: 'Cesar',
fruitInBasket: 9114
}
}
const homes = {
1: {
familyMembers: [1, 2, 3]
},
2: {
familyMembers: [1,2]
}
}
Object.keys(homes).forEach(function(k){
homes[k].familyMembers.sort((a,b)=>people[a].fruitInBasket - people[b].fruitInBasket)
})
console.log(homes)
I am making a call to two end points and need to display all the companies with their funds,name and factory that produces for that company.
here is the response from one end point
let factories = [
{
id: 1,
name: "Xintang",
short: "xin",
companies: [0, 4, 101,198]
},
{
id: 2,
name: "Ohio Plant",
short: "OHP",
companies: [22, 27]
},
{
id: 3,
name: "Cincy",
short: "Cin",
companies: []
}
];
Here is the response from the second
let companies = [
{
id: 0,
fund: "79588.96",
name: "Microsoft"
},
{
id: 1,
fund: "166727.06",
name: "Comcast"
},
{
id: 2,
fund: "131206.88",
name: "Apple"
},
{
id: 3,
fund: "74095.75",
name: "HP"
},
{
id: 4,
fund: "142556.86",
name: "Dell"
}
];
the dataset is much bigger, but here is just a sample. So I want be able to create a new object that links the factory with the specific company. Is there a way I can map over the companies and check which factory has the company id in that nested array so that I can add a new property factory to the company, and have a new array of objects that would look like this.
let returnedArr = [
{
id: 0,
fund: "79588.96",
name: "Microsoft",
factory: "Xintang"
},
{
id: 4,
fund: "142556.86",
name: "Dell",
factory: "Xintang"
}
];
You can do the following using reduce and Map.
Get the company-id and factory-name Map -> Then loop through the companies and create the output
let factories = [{id:1,name:"Xintang",short:"xin",companies:[0,4,101,198]},{id:2,name:"Ohio Plant",short:"OHP",companies:[22,27]},{id:3,name:"Cincy",short:"Cin",companies:[]}],
companies = [{id:0,fund:"79588.96",name:"Microsoft"},{id:1,fund:"166727.06",name:"Comcast"},{id:2,fund:"131206.88",name:"Apple"},{id:3,fund:"74095.75",name:"HP"},{id:4,fund:"142556.86",name:"Dell"}]
/*Get the company id: factory name mapping*/
const map = factories.reduce((m, f) =>
(f.companies.forEach(c => m.set(c, f.name)), m)
, new Map);
const output = companies.map(c => ({...c, factory: map.get(c.id) || ''}));
console.log(output)
Try This.... It may help u...
let result = [];
companies.forEach(company => {
let tempCompany = {...company};
factories.forEach(factory => {
let tempArray = factory.companies.filter(item => item === company.id);
if(tempArray.length > 0) {
tempCompany.factory = factory.name;
}
});
result.push(tempCompany);
});
One way to do this is to create a map of company ids to factory ids, then just iterate through your companies array and add the corresponding factory to the company object, like so:
The big advantage of this is that your factoryid lookups will be O(1), and it is O(n) to build the map. Your entire algorithm will be O(n). This makes this extremely fast even for very large data sets.
let factories = [
{
id: 1,
name: "Xintang",
short: "xin",
companies: [0, 4, 101,198]
},
{
id: 2,
name: "Ohio Plant",
short: "OHP",
companies: [22, 27]
},
{
id: 3,
name: "Cincy",
short: "Cin",
companies: []
}
];
let companies = [
{
id: 0,
fund: "79588.96",
name: "Microsoft"
},
{
id: 1,
fund: "166727.06",
name: "Comcast"
},
{
id: 2,
fund: "131206.88",
name: "Apple"
},
{
id: 3,
fund: "74095.75",
name: "HP"
},
{
id: 4,
fund: "142556.86",
name: "Dell"
}
];
var factoryMap = factories.reduce((res, curr) => {
return Object.assign(res, curr.companies.reduce((_res, _curr) => (_res[_curr] = curr.name, res), {}))
}, {});
var mappedCompanies = companies.map(company => Object.assign(company, {factory: factoryMap[company.id] || ""}));
console.log(mappedCompanies);
Assuming that a company can have more than one factory.
Try the following
let factories = [{
id: 1,
name: "Xintang",
short: "xin",
companies: [0, 4, 101, 198]
},
{
id: 2,
name: "Ohio Plant",
short: "OHP",
companies: [22, 27]
},
{
id: 3,
name: "Cincy",
short: "Cin",
companies: []
}
];
let companies = [{
id: 0,
fund: "79588.96",
name: "Microsoft"
},
{
id: 1,
fund: "166727.06",
name: "Comcast"
},
{
id: 2,
fund: "131206.88",
name: "Apple"
},
{
id: 3,
fund: "74095.75",
name: "HP"
},
{
id: 4,
fund: "142556.86",
name: "Dell"
}
];
let returnedArr = companies.map(company => {
company.factories = factories
.filter(factory => factory.companies.includes(company.id))
.map(factory => factory.name);
return company;
});
console.log(JSON.stringify(returnedArr, null, 4));