Take the average of an array items - javascript

Try to get average of values. I have json data going inside that, grabbing the array and using the average function on it. But error returns...
TypeError: arr.reduce is not a function
It's from first console.log(myArray) as per screenshot below. and second console.log with avg function, not working...
data() {
return {
myArray:[],
}
},
methods: {
avgArray: function(){
const sum = arr => arr.reduce((a,c) => (a + c));
const avg = arr => sum(arr) / arr.length;
this.estates.forEach((a, index) => {
this.myArray = a.m2_price;
console.log(this.myArray);
});
console.log(avg(this.myArray));
}
}

avgArray: function(){
const sum = arr => arr.reduce((a,c) => (a += c),0); // add equals and init with 0
const avg = arr => sum(arr) / arr.length;
this.myArray = this.estates.map(a => a.m2_price)
console.log(avg(this.myArray));
}
You were setting this.myArray as a value and not an array. You could've either pushed the m2_price or map it like above
Reduce function only exists on arrays. Clearly you were logging this.myArray and getting integers. Hence the error.

That is what reduce is for
const average = array => (array && array.length) ? (array.reduce((sum, item) => sum + item, 0) / array.length) : undefined;
console.log(average([1,2,3,4,5,6]));
export the average function from a file called average.js
Applied to your situation
import { average } from 'pathToYourIncludeLibrary/average';
data() {
return {
myArray:[],
}
},
methods: {
avgArray: () => average(this.myArray)
}

Related

Recursive function on sorted array returns undefined

I'm attempting to solve this problem recursively: Clean the room function: given an input of [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20], make a function that organizes these into individual array that is ordered. For example answer(ArrayFromAbove) should return: [[1,1,1,1],[2,2,2], 4,5,10,[20,20], 391, 392,591]
Array:
const array1 = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
array1.sort((a,b) => a-b);
Main Function:
const sortArray = (mainArr) => {
let acc = [];
console.log(acc, "acc");
const recursive = (arr) => {
if (arr.length > 1) {
console.log("inside func2 ", acc);
let likeArr = singArr(arr, arr[0]);
console.log(likeArr, "like");
arr = deleteVal(arr, arr[0]);
acc.push(likeArr);
return recursive(mainArr);
}
else {
return acc;
}
}
};
Helper Functions:
const singArr = (arr1, val) => {
let returnVal = arr1.filter(num => num === val);
return (returnVal.length === 1 ? returnVal[0] : returnVal);
};
const deleteVal = (arr, val) => {
let returnVal = arr.filter(num => num !== val);
return returnVal
};
Idea is to go through the array that I've sorted, filter using the first item in the array to get back a new array (single value if there's only one) with the like items, push it to my accumulator and then delete every instance of it in the original array.
I'm trying to do this recursively until there are no items left in the original array but it's returning undefined.
Any ideas where I'm going wrong?
inside your recursive function you are doing
return recursive(mainArr);
instead try to return recursive(arr);
You're not calling the recursive function from outside of the function.
const sortArray = (mainArr) => {
let acc = [];
console.log(acc, "acc");
const recursive = (arr) => {
if (arr.length > 1) {
console.log("inside func2 ", acc);
let likeArr = singArr(arr, arr[0]);
console.log(likeArr, "like");
arr = deleteVal(arr, arr[0]);
acc.push(likeArr);
return recursive(mainArr);
}
else {
return acc;
}
}
return recursive(mainArr)
};
Also, I believe the code posted doesn't return the desired output. You can probably do the following:
const array1 = [1,2,4,591,392,391,2,5,10,2,1,1,1,20,20];
array1.sort((a,b) => a-b);
const map = new Map();
array1.forEach((item) => {
if(map.has(item)) {
const storedItem = map.get(item);
map.set(item, Array.isArray(storedItem) ? [...storedItem, item] : [storedItem, item])
} else {
map.set(item, item);
}
});
console.log(Array.from(map.values()))
You never call the function recursive.
const sortArray = (mainArr) => {
let acc = [];
console.log(acc, "acc");
const recursive = (arr) => {
if (arr.length > 1) {
console.log("inside func2 ", acc);
let likeArr = singArr(arr, arr[0]);
console.log(likeArr, "like");
arr = deleteVal(arr, arr[0]);
acc.push(likeArr);
return recursive(mainArr);
}
else {
return acc;
}
}
recursive(mainArr) //<--- Call it!
};
You will also notice that sortArray does not return anything, so you may want to change recursive(mainArr) to return recursive(mainArr) to get a return.
Of note, the code does not produce the desired result, but this fix should get you going.

Javascript nested array: halve items and sum them up

I'm trying to create a function which returns me halve the data sumed up. I was able to do it on a non-nested Array but failing on the nested Array. I get the error Cannot read properties of undefined (reading 'push').
How the returned data should look like:
var data = [{"Key":1,"values":[
{"LastOnline":"21-11-29","Value":2},
{"LastOnline":"21-12-01","Value":2},
{"LastOnline":"21-12-03","Value":2}
]}];
What I have right now:
var data = [{"Key":1,"values":[
{"LastOnline":"21-11-28","Value":1},
{"LastOnline":"21-11-29","Value":1},
{"LastOnline":"21-11-30","Value":1},
{"LastOnline":"21-12-01","Value":1},
{"LastOnline":"21-12-02","Value":1},
{"LastOnline":"21-12-03","Value":1},
]}];
function halveMonth(data){
var newData = [];
var temp = [{"key":data.key,"values":[{}]}];
// sum 2 togheter
for(var i=1;i<data.values.length;i++){
if(data.values[i]){
temp.values[i].push({"LastOnline":data.values[i].LastOnline, "Value":(data.values[i].Value + data.values[[i-1]].Value)});
}
}
for(var i=0;i<temp.values.length;i++){
if(i % 2 == 0){
newData.push(temp.values[i]);
}
}
return newData;
}
console.log(halveMonth(data));
JS variables are case sensitive. Keep the key consistent everywhere. If you don't plan to use reduce here is the solution.
var data = [{"key":1,"values":[
{"LastOnline":"21-11-28","Value":1},
{"LastOnline":"21-11-29","Value":1},
{"LastOnline":"21-11-30","Value":1},
{"LastOnline":"21-12-01","Value":1},
{"LastOnline":"21-12-02","Value":1},
{"LastOnline":"21-12-03","Value":1},
]}];
function halveMonth(data){
let newData = []
for (let i = 0; i < data.length; i++) {
let temp = {"key":data[i].key,"values":[]}
for (let j = 0; j < data[i].values.length; j += 2) {
const res = (j+1===data[i].values.length) ? data[i].values[j].Value : data[i].values[j].Value + data[i].values[j+1].Value
temp.values.push({"LastOnline":(j+1===data[i].values.length)?data[i].values[j].LastOnline:data[i].values[j+1].LastOnline,"Value":res});
}
newData.push(temp);
}
return newData
}
console.log(halveMonth(data));
The variable data you declare at the first line of your snippet is an array. So you can't do data.values. You first need to indicate which index of your array you want to read. In this case : data[0].values
First things first, you data is itself an array - so assuming your real data has more than 1 element you'll need to do the same thing for each one.
It's helpful to start off with a method which does the work on just 1 element
const justASingle = {"Key":1,"values":[{"LastOnline":"21-11-28","Value":1},{"LastOnline":"21-11-29","Value":1},{"LastOnline":"21-11-30","Value":1},{"LastOnline":"21-12-01","Value":1},{"LastOnline":"21-12-02","Value":1},{"LastOnline":"21-12-03","Value":1}]};
function halveMonthSingle(data) {
return {
...data,
values: data.values.reduce((acc, item, idx) => {
if ((idx % 2) != 0)
acc.push({
...item,
Value: data.values[idx - 1].Value + item.Value
})
return acc;
}, [])
}
}
console.log(halveMonthSingle(justASingle))
Once you have that you can just use map do do it for every element
const data = [{"Key":1,"values":[{"LastOnline":"21-11-28","Value":1},{"LastOnline":"21-11-29","Value":1},{"LastOnline":"21-11-30","Value":1},{"LastOnline":"21-12-01","Value":1},{"LastOnline":"21-12-02","Value":1},{"LastOnline":"21-12-03","Value":1}]}];
function halveMonthSingle(data) {
return {
...data,
values: data.values.reduce((acc, item, idx) => {
if ((idx % 2) != 0)
acc.push({
...item,
Value: data.values[idx - 1].Value + item.Value
})
return acc;
}, [])
}
}
const result = data.map(halveMonthSingle)
console.log(result)
I would use reduce - saves me from trying to figure out why your two loops do not work other than data.values should be data[0].values
var data = [{"Key":1,"values":[{"LastOnline":"21-11-28","Value":1},{"LastOnline":"21-11-29","Value":1},{"LastOnline":"21-11-30","Value":1},{"LastOnline":"21-12-01","Value":1},{"LastOnline":"21-12-02","Value":1},{"LastOnline":"21-12-03","Value":1},]}];
const newArr = data.slice(0); // to not mutate original
newArr[0].values = data[0].values.reduce((acc,item,i) => {
if (i%2 !== 0) { // every second
acc.push(data[0].values[i]); // push the item
acc[acc.length-1].Value += data[0].values[i-1].Value; // add the first
}
return acc
},[])
console.log(newArr)
This works too. I basically did your idea, skipping the temp array and merging the two steps into one.
const data = [{"Key":1,"values":[
{"LastOnline":"21-11-28","Value":1},
{"LastOnline":"21-11-29","Value":1},
{"LastOnline":"21-11-30","Value":1},
{"LastOnline":"21-12-01","Value":1},
{"LastOnline":"21-12-02","Value":1},
{"LastOnline":"21-12-03","Value":1},
]}];
function halveMonth(data) {
const newData = [];
newData.push({
Key: data[0].Key,
values: []
});
for(let i = 0; i < data[0].values.length; i++){
if (i % 2 !== 0) {
newData[0].values.push({
LastOnline: data[0].values[i].LastOnline,
Value: data[0].values[i].Value + data[0].values[i-1].Value
});
}
}
return newData;
}
console.log(halveMonth(data));

This question is about an exercise in the book Eloquent JavaScript

The last part to this exercise is to write a recursive function that takes two parameters, a joined list and an index respectively. The function will find the value in the object within the list at it's respective index. The code i have written works the way i want (i can see it working when i console.log for every occasion the function is called. But on the last occasion it refers undefined as my value. I cannot understand why. Oh and it works for index of 0. code as followed.
and first, list looks like this:
list = {
value: 1,
rest: {
value: 2,
rest: {
value: 3,
rest: null
}
}
};
const nth = (list, targetNum) => {
let value = Object.values(list)[0];
if (targetNum == 0) {
return value;
} else {
targetNum = targetNum -1;
list = Object.values(list)[1];
// console.log(value);
// console.log(targetNum);
// console.log(list);
nth(list, targetNum);
}
};
console.log(nth(arrayToList([1,2,3]),2));
below is the code for arrayToList it was the first part of the exercise and if you have any comments that's cool, cause the hints ended up suggesting to build the list from the end.
const arrayToList = (arr) => {
let list = {
value: arr[0],
rest: nestObject()
};
function nestObject() {
let rest = {};
arr.shift();
const length = arr.length;
if (length == 1) {
rest.value = arr[0];
rest.rest = null;
} else {
rest.value = arr[0];
rest.rest = nestObject();
}
return rest;
}
return list;
};
Both solutions are convoluted and unnecessary verbose. Actually, both functions could be one-liners. Here are a few hints:
For the toList thing consider the following:
if the input array is empty, return null (base case)
otherwise, split the input array into the "head" (=the first element) and "tail" (=the rest). For example, [1,2,3,4] => 1 and [2,3,4]
return an object with value equal to "head" and rest equal to toList applied to the "tail" (recursion)
On a more advanced note, the split can be done right in the function signature with destructuring:
const toList = ([head=null, ...tail]) => ...
Similarly for nth(list, N)
if N is zero, return list.value (base case)
otherwise, return an application of nth with arguments list.rest and N-1 (recursion)
Again, the signature can benefit from destructuring:
const nth = ({value, rest}, n) =>
Full code, if you're interested:
const toList = ([value = null, ...rest]) =>
value === null
? null
: {value, rest: toList(rest)}
const nth = ({value, rest}, n) =>
n === 0
? value
: nth(rest, n - 1)
//
let lst = toList(['a', 'b', 'c', 'd', 'e', 'f'])
// or simply toList('abcdef')
console.log(lst)
console.log(nth(lst, 0))
console.log(nth(lst, 4))
You simply need to add a return when recursively calling nth. Otherwise the logic is carried out but no value is returned (unless targetNum is 0)
const nth = (list, targetNum) => {
let value = Object.values(list)[0];
if (targetNum == 0) {
return value;
} else {
targetNum = targetNum -1;
list = Object.values(list)[1];
return nth(list, targetNum); // return needed here too
}
};
Or more succinctly:
const nth = (list, n) => n === 0 ? list.value : nth(list.rest, n - 1)
Here's another non-recursive arrayToList that builds the list from the end:
const arrayToList = arr => arr.slice().reverse().reduce((rest, value) => ({value, rest}), null);
(The slice here is just to make a copy of the array so that the original is not reversed in place.)
Georg’s recursive solutions are beautiful!
I’d like to add the hinted “build the list from the end” solution from the book:
const arrayToList => (arr) => {
var list
while (arr.length) {
list = {value: arr.pop(), rest: list}
}
return list
}

Javascript map, reduce not working when implemented within object method

Based on the answer from this question I implemented the map reduce code within an object method.
this.displayValueGraph = async () => {
let scaleData = [];
this.positions.forEach(async (pos, i) => {
scaleData[i] = [];
let gdata = await pos.graphData;
gdata.option.forEach((d) => {
scaleData[i].push(d.map((x) => x * pos.size));
});
});
let out;
if (scaleData.length == 1) {
out = scaleData[0];
} else {
out = scaleData.reduce((a, b) => b.map((x, j) => x.map((v, k) => a[j][k] + v)));
}
};
The code by itself works fine. I have taken the input data (above scaleData) and run it through the map reduce function and the output is as expected. But if I include it as part of this method it does nothing. It doesn't throw any errors, it simply returns an empty array.
I have tried adding an empty array as an "initial value", but it doesn't help.
The root cause of the problem appears to have been the first forEach loop, where I included an await. I replaced the forEach with for in and it solved the problem.
this.displayValueGraph = async () => {
let scaleData = [];
for (const i in this.positions) {
const pos = this.positions[i];
scaleData[i] = [];
let gdata = await pos.graphData;
gdata.option.forEach((d) => {
scaleData[i].push(d.map((x) => x * pos.size));
});
}
let out;
if (scaleData.length == 1) {
out = scaleData[0];
} else {
out = scaleData.reduce((a, b) => b.map((x, j) => x.map((v, k) => a[j][k] + v)));
}
};

in the easiest and most concise way as possible

I want to sort an array values in an ascending or descending order without using sort().
I have created a function, however I am not satisfied with it.
I believe the code below could be much shorter and more concise.
Please let me know where to modify or you may entirely change the code too. Thank you in advance.
const func = arg => {
let flip = false;
let copy = [];
for(let val of arg) copy[copy.length] = val;
for(let i=0; i<arg.length; i++) {
const previous = arg[i-1];
const current = arg[i];
if(previous > current) {
flip = true;
copy[i] = previous;
copy[i-1] = current;
}
}
if(flip) return func(copy);
return copy;
};
l(func([5,2,8,1,9,4,7,3,6]));
If your input is composed of whole numbers, as in the example, pne option is to reduce the array into an object, whose keys are the numbers, and whose values are the number of times those values have occured so far. Then, iterate over the object (whose Object.entries will iterate in ascending numeric key order, for whole number keys), and create the array to return:
const func = arr => {
const valuesObj = {};
arr.forEach((num) => {
valuesObj[num] = (valuesObj[num] || 0) + 1;
});
return Object.entries(valuesObj)
.flatMap(
([num, count]) => Array(count).fill(num)
);
};
console.log(
func([5,2,8,1,9,10,10,11,4,7,3,6])
);
This runs in O(N) time.
To account for negative integers as well while keeping O(N) runtime, create another object for negatives:
const func = arr => {
const valuesObj = {};
const negativeValuesObj = {};
arr.forEach((num) => {
if (num >= 0) valuesObj[num] = (valuesObj[num] || 0) + 1;
else negativeValuesObj[-num] = (negativeValuesObj[-num] || 0) + 1;
});
return [
...Object.entries(negativeValuesObj).reverse()
.flatMap(
([num, count]) => Array(count).fill(-num)
),
...Object.entries(valuesObj)
.flatMap(
([num, count]) => Array(count).fill(num)
)
];
};
console.log(
func([5,2,8,1,-5, -1, 9,10,10,11,4,7,3,6, -10])
);
For non-integer items, you'll have to use a different algorithm with higher computational complexity.

Categories

Resources