Function trims values after being passed in another function - javascript

I would like have renderData() display the values from max. When I console.log(max) in calculateData() it displays all three maximum values from three JSON objects. However, when I return max in renderData() it only shows the first value. Why is this, and what can I do to make it display all three values instead of just one? Note: data is the json list of objects being passed. Thank you!
function calculateData(data) {
for (i in data) {
var arr = [];
var max;
var obj = data[i].tones;
obj.map(function(item) {
var data = item.score;
arr.push(data);
})
max = arr.reduce(function(a, b) {
return Math.max(a, b);
})
//Returns an array containing dominant [emotion_tone, language_tone, social_tone]
return renderData(max);
}
}
function renderData(max) {
console.log(max);
};

Maybe this is what you are intending? It will iterate through the entire data object calculating a max for each iteration, collect them in an array, and then finally call the renderData func with that array.
function calculateData(data) {
var maxes = [];
for (i in data) {
var arr = [];
var max;
var obj = data[i].tones;
obj.map(function(item) {
var data = item.score;
arr.push(data);
})
maxes.push(arr.reduce(function(a, b) {
return Math.max(a, b);
}));
}
return renderData(maxes);
}
function renderData(max) {
console.log(max);
};

I created a second array, finalArray and pushed each max into it:
function calculateData(data) {
var finalArr = [];
for (i in data) {
var arr = [];
var max;
data[i].tones.map(function(item) {
arr.push(item.score);
})
var max = arr.reduce(function(a, b) {
return Math.max(a, b);
});
finalArr.push(max);
//Returns an array containing dominant [emotion_tone, language_tone, social_tone]
// return renderData(max);
}
renderData(finalArr);
}
function renderData(finalArr) {
console.log(finalArr);
};
Thanks for your help guys!

Your error arises because the return statement inside the loop aborts the whole function, and therefore also the loop. But this whole function can be simplified/shortened quite a bit:
And as mentioned in the comments, don't define functions inside a loop (unless it is inevitable), define the before the loop. I did this in by defining the functions getScore and max in my code.
//ES6
function calculateData(data) {
var getScore = item => item.score,
max = (a,b) => Math.max(a,b),
maxima = Object.values(data)
.map(value => value.tones.map(getScore).reduce(max));
return renderData(maxima);
}
//Or maybe you're more comfortable without Arrow functions
function calculateData(data) {
function getScore(item){ return item.score }
function max(a,b){ return Math.max(a,b) }
var maxima = Object.values(data).map(function(value){
return value.tones.map(getScore).reduce(max)
});
return renderData(maxima);
}
The only difference to your code is that Object.values() returns only own values of the object, whereas for..in iterates over all values of the object, own and inherited.

Related

how to sum an array of arrays in javascript

I currently have this function
function radius(d) {
return d.values[0].environment["4*"];
console.log(d);
}
However id liked to be able to average all of the 4* environment values for each document(there are 6 in the example below) and return this as the radius. Im new to JS so no idea how to do this. can you help. here is the structure of the data
You can use reduce function:
function radius(d) {
return d.values.reduce(function(avg, item, index, array) {
return avg + item.environtment['4*'] /array.length
},0)
}
It's tough to answer the question accurately without testing the whole data structure. Based on what you've provided this should work:
function radius(d) {
let sum = 0;
for (let i=0; i<d.length; i++) {
let num = parseInt(d[i].environment['4*']);
if (!isNaN(num)) sum += num;
}
return sum;
}
We loop through the array, and if environment['4*'] is a valid number we sum it up. Functionally it would be:
function radius(d) {
const filtered = d.values.filter((x) => {
let num = parseInt(x.environment['4*']);
return !isNaN(num);
});
const sum = filtered.reduce((acc, val) => {
return acc+val;
},0)
return sum/filtered.length;
}

Javascript return reference to array index with primitive value

I want to return a reference to to the content of an array at index x in order to be able to change the content of the array using the returned index afterwards.
Here is an example of what I mean:
let testArr = [1,2,3]
const someFunct = arr => {
...
return {reference to arr[0], aka 1}
}
someFunct(testArr) = 0;
//should log [0,2,3]
console.log(testArr);
someFunct(testArr) should behave like arr[0] in this case.
The content of the array could be anything.
i dont think the exact implementation you are trying to achieve is possible in JavaScript.
https://medium.com/#naveenkarippai/learning-how-references-work-in-javascript-a066a4e15600
something similar:
const testArr = [1,2,3]
const changeArray = (array, index, newValue) => {
array[index] = newValue
return array
}
changeArray(testArr, 0, 0) // evaluates to [0,2,3]
I want to return a reference …
This is not possible, JavaScript doesn't have references as returnable values. The someFunct(testArr) = 0; syntax you are imagining is invalid.
Instead, take the new value as an argument:
function someFunct(arr, val) {
…
arr[0] = val;
}
someFunct(testArr, 0);
or return an object with a method that does the assigning:
function someFunct(arr) {
…
return {
set(v) {
arr[0] = v;
}
};
}
someFunct(testArr) = 0;
Try this:
function arrayWrapper(arr, index, newVal) {
let returnVal;
if(newVal) {
arr[index] = newVal;
returnVal = arr;
} else {
const obj = { ...arr };
returnVal = obj[index];
}
return returnVal;
};
console.log(arrayWrapper([1,2,3,4,5,6,7,8,9], 5)); /// to get value at index
console.log(arrayWrapper([1,2,3,4,5,6,7,8,9], 5, 'text')); // to set value on index
You can use the above method to get as well as set elements to your array.
The nature of operation depends on the third parameter.
Hope this helps :)

Difference between normal for loop and for...in?

I'm trying to write a function to fulfil the following requirements:
Given an object and a key, "getElementsThatEqual10AtProperty" returns an array containing all the elements of the array located at the given key that are equal to ten.
Notes:
If the array is empty, it should return an empty array.
If the array contains no elements are equal to 10, it should return
an empty array.
If the property at the given key is not an array, it should return an
empty array.
If there is no property at the key, it should return an empty array.
Example:
var obj = {
key: [1000, 10, 50, 10]
};
var output = getElementsThatEqual10AtProperty(obj, 'key');
console.log(output); // --> [10, 10]
Approach #1 (fails the final point *If there is no property at the key, it should return an empty array.):
function getElementsThatEqual10AtProperty(obj, key) {
var output = [];
for (var i = 0; i < obj[key].length; i++) {
if (obj[key][i] === 10) {
output.push(obj[key][i]);
}
}
return output;
}
Approach #2 passes all:
function getElementsThatEqual10AtProperty(obj, key) {
var output = [];
for (let i in obj[key]) {
if (obj[key][i] === 10) {
output.push(obj[key][i]);
}
}
return output;
}
From my understanding, both loops and the subsequent conditional push has the same logic. Why does one work over the other?
You're making this more complicated than it needs to be. I would just do this:
function getSameVals(yourArray, val){
var a = [];
for(var i=0,l=yourArray.length; i<l; i++){
if(yourArray[i] === val){
a.push(val);
}
}
return a;
}
var ten = getSameVals(obj.key, 10);
console.log(ten);

JavaScript changing object list to array. return undefined

function listToArray(list){
var newArray = [];
repeat();
function repeat(){
newArray.push(list.value);
if(list.rest == null){
return obj = newArray; // I don't know why It returns undefined here
}
else {
list = list.rest;
repeat();
}
}
}
// and this will return an array
function reTurn(){
var listVar = [5, 4, 3, 2, 1];
return obj = listVar;
}
This function does change my obj when I look for it in console, but returns undefined.
Anyone can help me? please
just return newArray - you can't return an assignment like that.
You're returning from the inner function, not the outer one. Add a return newArray to the bottom of listToArray. Change the return statement in repeat to just return;.
function listToArray(list){
var newArray = [];
repeat();
function repeat(){
newArray.push(list.value);
if (list.rest) {
list = list.rest;
repeat();
}
}
return newArray;
}
There's nothing really wrong with the recursive approach, but it's not necessary. You could just as easily write
function listToArray(list){
var newArray = [];
while (list) {
newArray.push(list.value);
list = list.rest;
}
return newArray;
}
However, even this code has the drawback that it is mixing the traversal of the list with the building of the array of values. It would be better to separate those:
function traverseList(list, fn) {
while (list) {
fn(list.value);
list = list.rest);
}
}
Now you can write listToArray as
function listToArray(list) {
var newArray = [];
traverseList(list, value => newArray.push(value));
return newArray;
}
I might also write this as a generator:
function* forList(list) {
while (list) {
yield list.value;
list = list.rest;
}
}
Now I don't even need a separate function to create the array of values, because I can just write
[...forList(list)]

knockout.js sorted observable array

I would like to have an observable array which will sort itself when an object is pushed into it (it would be even better if it would sort itself if any of the values it was using in the comparator function was changed).
Something where you could define the comparator function you want the array to sort on and then every time push was called it would add the pushed objects into the correct place in the array so the array remained sorted, like:
var sortedArray = ko.sortedObservableArray(
function (a,b) { return b - a;},
[1,7,4]
); // sortedArray will be [1,4,7]
sortedArray.push([5,2]); // sortedArray will now be [1,2,4,5,7]
Are there any libraries that will do this for me and if not what is the best way to go about implementing this?
I ended up creating a sorted observable array by extending knockout observable array:
ko.sortedObservableArray = function (sortComparator, initialValues) {
if (arguments.length < 2) {
initialValues = [];
}
var result = ko.observableArray(initialValues);
ko.utils.extend(result, ko.sortedObservableArray.fn);
delete result.unshift;
result.sort(sortComparator);
return result;
};
ko.sortedObservableArray.fn = {
push: function (values) {
if (!$.isArray(values)) {
values = [values];
}
var underlyingArray = this.peek();
this.valueWillMutate();
underlyingArray.push.apply(underlyingArray, values);
underlyingArray.sort(this.sortComparator);
this.valueHasMutated();
},
sort: function (sortComparator) {
var underlyingArray = this.peek();
this.valueWillMutate();
this.sortComparator = sortComparator;
underlyingArray.sort(this.sortComparator);
this.valueHasMutated();
},
reinitialise: function (values) {
if (!$.isArray(values)) {
values = [values];
}
var underlyingArray = this.peek();
this.valueWillMutate();
underlyingArray.splice(0, underlyingArray.length);
underlyingArray.push.apply(underlyingArray, values);
underlyingArray.sort(this.sortComparator);
this.valueHasMutated();
},
reverse: function () {
var underlyingArrayClone = this.peek().slice();
underlyingArrayClone.reverse();
return underlyingArrayClone;
}
};
Which can be used in the following way:
var sortedArray = ko.sortedObservableArray(
function (a,b) { return a - b;},
[1,7,4]
); // sortedArray will be [1,4,7]
sortedArray.push([5,2]); // sortedArray will now be [1,2,4,5,7]
sortedArray.sort(function (a,b){
return b - a;
}); // sortedArray will now be [7,5,4,2,1]
sortedArray.push(6); // sortedArray will now be [7,6,5,4,2,1]
The only problem I have is that when reinitialising the sorted observable array with a new array in the same way you would reinitialise an observable array the sorted observable array isn't being sorted. To get around this I have added a reinitialise function on the sorted observable array:
var sortedArray = ko.sortedObservableArray(
function (a,b) { return a - b;},
[1,7,4]
); // sortedArray will be [1,4,7]
sortedArray([3,2,8]); // this doesn't work correctly, sortedArray will be [3,2,8]
// instead of [2,3,8]
// To get around this you can use reinitialise()
sortedArray.reinitialise([3,2,8]); // sortedArray will be [2,3,8]
Try this:
var sortedArray = ko.observableArray();
sortedArray.subscribe(function () {
if (!sortedArray._isSorting) {
sortedArray._isSorting = true;
sortedArray.sort(function (a, b) { return b - a; });
sortedArray._isSorting = false;
}
});
You can wrap this up in a function to create new sorted observable arrays whenever you want.

Categories

Resources