So, long story short, I have an object with subjects and students' grades. My job is to:
1. Calculate the average for each subject.
2. Sum up all the averages;
3. Calculate the totalAverage on all subjects.
here is my code:
const grades = {
algebra: [2,3,5,2,4,3],
geometry: [2,4,5],
signing: [3,3,4,5],
physics: [5,5],
music: [2,2,5],
english: [4,4,3],
poetry: [5,3,4],
chemistry: [2],
french: [4,4]
}
function getAverageScore(data) {
for (let subject in data) {
let grades = data[subject];
let average = grades.reduce((acc,curr) => {
return acc + curr / grades.length;
}, 0)
For some odd reason, this doesn't work, however, when I console.log (grades.length) it shows the length of an array with grades. What am I doing wrong? Also, how can I sum all the average grades in a resulting object? Any suggestions?
Here's a solution:
function getAverageScore(data) {
const listOfSubjects = Object.keys(data);
let averagePerSubject = {};
let sumOfAllAverages = listOfSubjects.reduce((sumOfAllAverages, subject) => {
let grades = data[subject];
let average = grades.reduce((acc,curr) => (acc + curr), 0) / grades.length;
averagePerSubject[subject] = average;
return sumOfAllAverages + average;
}, 0);
let averageOfAllSubjects = sumOfAllAverages / listOfSubjects.length;
return { averagePerSubject, sumOfAllAverages, averageOfAllSubjects };
}
The implementation though, shows the average of all subjects, not a weighted average.
You can use reduce method to get the desired result:
const grades = {
algebra: [2,3,5,2,4,3],
geometry: [2,4,5],
signing: [3,3,4,5],
physics: [5,5],
music: [2,2,5],
english: [4,4,3],
poetry: [5,3,4],
chemistry: [2],
french: [4,4]
};
/*
1. Calculate the average for each subject.
2. Sum up all the averages;
3. Calculate the totalAverage on all subjects.
*/
const avgBySubject = Object.entries(grades).reduce((a, [k, v]) => {
a[k] = a[k] || 0;
a[k] = v.reduce((acc, curr) => {
acc +=curr;
return acc;
} ,0) / v.length;
return a;
}, {});
console.log(`avg by subject is `, avgBySubject);
const sumAllAverages = Object.values(avgBySubject).reduce((a,c) => {
a += c || 0;
return a;
}, 0);
console.log(`sumAllAverages is ${sumAllAverages}`);
const theTotalAverage = sumAllAverages / Object.values(avgBySubject).length;
console.log(`theTotalAverage is: `, theTotalAverage);
I have written solution for your problem:
function getAverageScore(data) {
let sumOfAverages = 0;
for (let subject in data) {
const grades = data[subject];
const sumOfGrades = grades.reduce((acc, curr) => {
return acc + curr;
}, 0);
const averageOfSubject = sumOfGrades / grades.length;
sumOfAverages += averageOfSubject;
}
const totalAverage = sumOfAverages / Object.keys(data).length;
return totalAverage;
}
I think that above solution is so clear and obvious.
In your code you tried use reduce() for calculate average in wrong way.
You divided every grade by number of grades (even several times, because when you add divided grade to sum of grades, you divided it in next iterations of reduce() function).
Related
How to return an array with the step of the sum of the previous value?
I have an input number that is 1000
I want to get [1000, 2000, 3000 ... 10000]
I'm trying to:
const range = (i: number, o: number) => {
const arr = [0, 1, 2, 3, 4].reduce(
(accumulator: any, currentValue: any, index: any, array: any) => {
console.log((array[index] = accumulator + currentValue));
return 1;
},
10000
);
};
range(1000, 10000);
Use Array.from and provide the first argument as an object with length property that is equal to the step, and second argument as mapping function that simply multiply the index and step:
const range = (start,end) =>
Array.from( {length: end/start} ,(_,i) => (i+1) * start )
console.log(range(1000,10000))
Try this:
function range(start, end) {
var arr = []; // Start with an empty array
/* Start a counter at the start value, and increment it
* by the start value while it is less than or equal to
* the end value. Push this value into arr each time
*/
for (let i = start; i <= end; i += start) {
arr.push(i);
}
return arr; // Return the array
}
Use simple loop and check if number * index <= max while adding values to new array:
const range = (number, max) => {
let index = 1;
let newArray = [];
do {
newArray.push(number * index);
index++;
} while (number * index <= max);
return newArray;
};
console.log(range(1000, 10000));
console.log(range(10000, 10000));
const range = (start, end) => {
let acc = [];
for (let i = start; i <= end; i = i + start) {
acc = [...acc, i];
}
return acc;
}
If not, please elaborate your example to clearly state the intent of ...step of the sum of the previous value.
The idea behind the script is as follows:
I am filtering the original array by removing all even values from it. Next, I form a new array from the partial products of the original array:
// new first element = 1 * 3;
// second = (first (previous multiplication) * current value) = 3 * 3 (9);
// third = (previous product * current value) = 9 * 9 (81)
I got the results I wanted, but my output doesn't look like an array:
Input:
3 3 9
Output:
3
9
81
Please help me draw the following output:
Input:
3 3 9
Output:
3 9 81
function modify(arr) {
var result = [];
arr = arr.filter(item => !(item % 2 == 0))
.reduce(function(acc, curItem) {
console.log(acc * curItem);
return acc * curItem;
}, 1)
for (let i = 0; i < result.length; i++) {
arr.push(result[i]);
};
return result;
}
console.log( modify([3,3,9]) )
You can use reduce keeping track of both your cumulative product, and the final array:
const input = [3, 3, 9];
const output = input.reduce( (acc,val) => {
const newResult = acc.cum * val;
acc.result.push(newResult);
acc.cum = newResult;
return acc;
},{cum:1, result:[]});
console.log(output.result);
As the last element of the array is always the cumulative product, you could also write it like this:
const input = [3, 3, 9];
const output = input.reduce( (acc,val) => {
const newResult = (acc.length ? acc[acc.length-1] : 1) * val;
acc.push(newResult);
return acc;
},[]);
console.log(output);
It's up to you which one of these you find easier to work with.
With Array#reduce() method and the spread operator you can transform your array as in the following demo:
let modify = (arr) => arr.reduce((acc,cur,i) => [...acc, (acc[i-1] || 1) * cur],[]);
console.log( modify([3,3,9]) );
Or simply:
function modify(arr) {
return arr.reduce(function(acc,cur,i) {
return [...acc, (acc[i-1] || 1) * cur]
}, []);
}
console.log( modify([3,3,9]) );
Or if this is code that runs once, in which case you don't need a function:
let oldArray = [3,3,9];
let newArray = oldArray.reduce(function(acc,cur,i) {
return [...acc, (acc[i-1] || 1) * cur]
}, []);
console.log( newArray );
I have an array of objects:
const bookDetails = [{"author":"john","readingTime":12123},
{"author":"romero","readingTime":908},
{"author":"romero","readingTime":1212},
{"author":"romero","readingTime":50},
{"author":"buck","readingTime":1902},
{"author":"buck","readingTime":12125},
{"author":"romero","readingTime":500},
{"author":"john","readingTime":10},
{"author":"romero","readingTime":230},
{"author":"romero","readingTime":189},
{"author":"legend","readingTime":12}
{"author":"john","readingTime":1890}]
I tried calculating the median for each author. Here is my function that calculates median for a given array:
//To calculate the median for a given array
function medianof2Arr(arr1) {
var concat = arr1;
concat = concat.sort(function (a, b) { return a - b });
var length = concat.length;
if (length % 2 == 1) {
// If length is odd
return concat[(length / 2) - .5]
} else {
return (concat[length / 2] + concat[(length / 2) - 1]) / 2;
}
}
But I want to calculate the median for each author separately. How can I do that?
Expected output
{"john": 1890, "romero": 365, "buck": 7014, "legend": 12}
Can you please try this
let bookDetails = [
{"author":"john","readingTime":12123},
{"author":"romero","readingTime":908},
{"author":"romero","readingTime":1212},
{"author":"romero","readingTime":50},
{"author":"buck","readingTime":1902},
{"author":"buck","readingTime":12125},
{"author":"romero","readingTime":500},
{"author":"john","readingTime":10},
{"author":"romero","readingTime":230},
{"author":"romero","readingTime":189},
{"author":"legend","readingTime":12},
{"author":"john","readingTime":1890}
];
const authorMap = bookDetails.reduce((acc, book) => {
acc[book.author] ? acc[book.author].push(book.readingTime) : acc[book.author] = [book.readingTime]
return acc;
}, {})
calculateMedian = (list) => {
const sortedList = list.sort((a, b) => a - b);
console.log(sortedList[Math.floor(sortedList.length / 2)]); // You might need to tweak this
}
for (let author in authorMap) {
calculateMedian(authorMap[author])
}
You could first group your input by author, to get this data structure:
{
"john": [12123, 10, 1890],
"romero": [908, 1212, 50, 500, 230, 189],
"buck": [1902, 12125],
"legend": [12]
}
And then you could call the median function on all those arrays and replace those arrays with the values you get back from the calls:
function median(arr) {
arr = [...arr].sort((a, b) => a - b);
let mid = arr.length >> 1;
return arr.length % 2 ? arr[mid] : (arr[mid-1] + arr[mid]) / 2;
}
const bookDetails = [{"author":"john","readingTime":12123}, {"author":"romero","readingTime":908}, {"author":"romero","readingTime":1212}, {"author":"romero","readingTime":50}, {"author":"buck","readingTime":1902}, {"author":"buck","readingTime":12125}, {"author":"romero","readingTime":500},{"author":"john","readingTime":10},{"author":"romero","readingTime":230}, {"author":"romero","readingTime":189}, {"author":"legend","readingTime":12},{"author":"john","readingTime":1890}];
// Create a key for each author, and link them with an empty array
let result = Object.fromEntries(bookDetails.map(({author}) => [author, []]));
// Populate those arrays with the relevant reading times
for (let {author, readingTime} of bookDetails) result[author].push(readingTime);
// Replace those arrays with their medians:
for (let author in result) result[author] = median(result[author]);
console.log(result);
Note that the median for buck is not an integer 7014 as in your expected output, but 7013.5
let numbers = [2, 2, 6, 10];
const findAvarage = (numbers) => {
let total = 0;
let checkIntegers = numbers.every(i => !Number.isInteger(i))
if (checkIntegers = true) {
for(let i = 0; i < numbers.length; i++) {
total += numbers[i];
}
let avg = total / numbers.length;
return avg
} else {
return "Only integers allowed"
}
const compareNumbers = (numbers) => {
}
In this code I calculate the avarage of the given numbers in array and now I want to find how many numbers in array are greater that avarage number with second function
I tried to use find method but it did not work out,any solutions on this please?
You can use filter function to filter out the numbers that are larger than average.
const avg = findAvarage(numbers)
const count = numbers.filter(number => number > avg).length
const compareNumbers = (numbers) => {
const avg = findAvarage(numbers);
let greater = 0;
numbers.forEach((num) => { if (num > avg) greater++; });
return greater;
}
u can use filter or reduce to solve it
let numbers = [2, 2, 6, 10];
function countNumbers(number){
return numbers.filter(num=> num>=number).length;
}
function countNumbers2(number){
return numbers.reduce((count,item)=>count+(item>=number),0)
}
console.log(countNumbers(7));
console.log(countNumbers2(3))
Javascript does not provide many extension methods that can be used for arrays, you have just some basics operations.
Your code can be more cleaner if you turn this need into extensions for arrays that you can them every where without calling functions, you can do as follow:
Object.defineProperties(Array.prototype, {
count: {
value: function(value) {
if(isNan(value)) return NaN;
return this.filter(x => x>=value).length;
}
},
average:{
value:function(){
let total = 0;
if(!this.every(i => Number.isInteger(i)))
return NaN;
for(let i = 0; i < numbers.length; i++) {
total += numbers[i];
}
return total/this.length;
}
}
});
and you can use it like this for you example
var result = numbers.count(numbers.average())
this way ?
const findAvarage=(a,b,c,d) => [a,b,c,d].reduceRight((t,n,i,a)=>
{
t += n
if (!i) t /= a.length
return t
},0)
, greaterOrEqualCount = (a,b,c,d) =>
{
let avg = findAvarage(a,b,c,d)
return [a,b,c,d].reduce((r,n)=>r+(n<avg?0:1),0)
}
console.log("count ",greaterOrEqualCount(2,2,6,10))
people, just got a quick question about a javascript problem I have. Here is the question posed:
Write a function named countAboveAverage that accepts an array of numbers and returns the count of how many values are more than the average of the same list of numbers. Your countAboveAverage function must call the arrayAverage function you wrote in the previous exercise.
Use the following to test your function.
let values = [31.9, 31.3, 42.4, 42.4, 60.8, 28.1];
console.log(countAboveAverage(values)); //expect 3
This is what I got so far.
let values = [31.9, 31.3, 42.4, 42.4, 60.8, 28.1];
const count = (arr) => {
let i = 1;
while(i <= arr){
i++;
}
};
const arrayAverage = (arr) => arr.reduce ((a,b) => a+b,0)/arr.length;
const countAboveAverage = (arr) => arrayAverage(arr) ? arrayAverage(arr).count: 0;
console.log(countAboveAverage(values)); //expect 3
Obviously it's not working. A little guidance will be much appreciated.
You can store the average value in a variable and then use it to get a count of elements greater than average
const countAboveAverage = (arr) => {
const average = arrayAverage(arr);
return arr.filter(i => i > average).length
}
arrayAverage is the function from your code snippet
let values = [31.9, 31.3, 42.4, 42.4, 60.8, 28.1];
const count = (arr) => {
let i = 1;
while(i <= arr.length){
i++;
}
};
const arrayAverage = (arr) => arr.reduce ((a,b) => a+b,0)/arr.length;
const countAboveAverage = (arr) => arrayAverage(arr);
let i=0;
let countAbove=0;
while(i <= values.length){
if(countAboveAverage(values)<values[i-1]){
countAbove++;
}
i++;
}
countAboveAverage(values)
console.log(countAbove);
Simply This will Work!! :)