Javascript map, reduce not working when implemented within object method - javascript

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)));
}
};

Related

Converting a for loop function results into an array

I am looping through an array of selected index comparing each value to a database of machine pricing, and returning the price of each selected index. the problem is, the result repData1 return individual results, I want those resuls to displayed in an array for I can manipulate the array.
I have tried push, concat.... string results is displayed for each item rather than a whole.
for (let a = 0; a < selectedindex.length; a++) {
wixData
.query('MachinePricing')
.contains('title', selectedindex[a])
.find()
.then(async (results) => {
if (results.items.length > 0) {
let repData = results.items;
let repData1 = repData.map(({ prices }) => prices);
console.log(repData1);
}
});
}
Don't loop async calls using iterators
Instead do this
const a = 0
const repData = [];
function getData = () => {
if (a >= selectedindex) {
processRepData();
return;
}
wixData
.query('MachinePricing')
.contains('title', selectedindex[a])
.find()
.then(results => {
if (results.items.length > 0) {
repData.concat(results.items.map(({prices}) => prices));
}
a++;
getData()
});
}
getData()
I think what you are doing is this (run a query for each selected index and extract the returned prices into an array):
const queries = selectedindex.map(ix => wixData
.query('MachinePricing')
.contains('title', ix)
.find())
const results = await Promise.all(queries)
const prices = results.flatMap(r => r.items.map(i => i.prices))

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.

Running forEach on Object.entries does not return the same thing as a for loop

I am iterating over an object using a regular for loop and that works fine for me. But, I was trying to remove all for loops of my code in favor of array iteration instead and, for some reason I can't understand why when using forEach I get a different result.
Note: forEach here is from a module called p-iteration
https://www.npmjs.com/package/p-iteration
This works fine, it returns the correct values.
for await (const [key, value] of Object.entries(tatGroupedByRegion)) {
onTarget = 0;
notOnTarget = 0;
const cases = [];
await forEach(value, async email => {
if (!cases.includes(email.new_name)) {
cases.push(email.new_name);
isOnTarget(email);
}
});
backlogData[key].tatd1 = percentage(onTarget, notOnTarget);
tatd1Total.value += parseInt(percentage(onTarget, notOnTarget), 10);
if ((parseInt(percentage(onTarget, notOnTarget) !== 0), 10)) {
tatd1Total.count += 1;
}
}
This does not work,this part here backlogData[key].tatd1 = percentage(onTarget, notOnTarget), returns the same value over and over.
await forEach(Object.entries(tatGroupedByRegion), async ([key, value]) => {
onTarget = 0;
notOnTarget = 0;
const cases = [];
await forEach(value, async email => {
if (!cases.includes(email.new_name)) {
cases.push(email.new_name);
isOnTarget(email);
}
});
backlogData[key].tatd1 = percentage(onTarget, notOnTarget);
tatd1Total.value += parseInt(percentage(onTarget, notOnTarget), 10);
if ((parseInt(percentage(onTarget, notOnTarget) !== 0), 10)) {
tatd1Total.count += 1;
}
});
exports.forEach = async (array, callback, thisArg) => {
const promiseArray = [];
for (let i = 0; i < array.length; i++) {
if (i in array) {
const p = Promise.resolve(array[i]).then((currentValue) => {
return callback.call(thisArg || this, currentValue, i, array);
});
promiseArray.push(p);
}
}
await Promise.all(promiseArray);
};
This is the implementation of forEach that you're using. The callback receives this as the first argument, this can be a problem.

Recursively calling a curried function in Javascript

As a toy example lets say we have this function and its usage:
const map = (f = n => n + 1) => (lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [f(...lst.splice(0,1)), ...map(f)(lst)];
}
const inc = n => n + 1;
const map_inc = map(inc);
map_inc([1,2,3]) // => (produces) [2,3,4]
Inside of the curried function map I am using "recursion" by calling map(f)(lst).
The example above rebuilds the function before it can be called.
Is it possible to do this recursion without rebuilding the function?
I know of this way:
y = (f = (f, ...args) => [...args],
...args) => f(f, ...args);
const map = (mapper = n => n + 1) => (self = mapper, lst = [1,2,3]) => {
if(lst.length === 0)
return [];
else
return [mapper(...lst.splice(0,1)), ...self(self, lst)];
}
const inc = n => n + 1;
const map_inc = (...args) => y(map(inc), ...args);
map_inc([1,2,3]) // => (produces) [2,3,4]
I do not really like how this requires the passing of the function to itself.
Can this be done without the y function and without passing the function to itself? Can this be done in a more point-free style?
If I'm understanding your question correctly, you can't return named arrow functions, but you can return a named regular function and call it recursively like this:
const reducer = k => function recurse(a, item) {
//...
const s_res = _.split(item, k, 1);
return recurse(a.withMutations(a => {
a.push(s_res[0]);
let a_element = document.createElement('a');
a_element.setAttribute('href', '#');
a_element.addEventListener('click', () => display_gen_element(k, obj));
a.push(a_element);
}), s_res[1]);
};
P.S. For the sake of readability please don't use one-letter variable names unless it's blindingly obvious what they're for, e.g. a counter in a for loop, etc.
If your purpose was remove the need to pass self to itself
...self(self, lst)
You can do this by adding 1 more function named recursor
const map = (mapper = n => n + 1) => (lst = [1, 2, 3]) => {
const recursor = lst => {
if (lst.length === 0) return [];
else return [mapper(...lst.splice(0, 1)), ...recursor(lst)];
};
return recursor(lst);
};
const inc = n => n + 1;
const map_inc = map(inc);
console.log(map_inc([1, 2, 3])); // => (produces) [2,3,4]
You didn't need the y combinator-like function called y at all.
recursor has mapper in its closure

Take the average of an array items

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)
}

Categories

Resources