I am trying to convert a dynamic formula in Javascript - javascript

this is not a regular JS tasks as I need help with JS and maths little bit. I got the math formula done but now I'm trying to get it in javascript.
I writing a calculator so I got var a,b,c and D.
D is the sum of A,B,C (Currently it is 825)
I changed the D from 825 to 600 so everything should reduce propotionaly but not B. B should stay as it is and A and C should reduce.
The following code below calculate correctly but I want to make it dynamic fully. Var newA and newC I can't seem to get the right variable in it as I need the newA to dive by 6 and New C to divide by 5/6.
Is there any genius good in math and javascript?
I also attached an image of the math formula if anyone can maybe write a better JS.
The idea is if that I can after add more variables and when I reduce the D it will let me know how much are the elements that can be reduced.
Here is the code:
// Variables
var a = 100;
var b = 225; // this variable does not change.
var c = 500;
// Container sum
var containerSum = a + b + c ;
// New container sum
var newContainerSum = 600;
// 825 - (100 + 500) = 225
var fixedElement = b;
// 600 - 225 = 375
var remainingElementsTotal = newContainerSum - fixedElement;
//Propotion calculate 100/500 = 1/5 = 0.2
var propotions = a/c;
var remainingPropotions = 1 - propotions;
var newA = remainingElementsTotal/6;
var newC = remainingElementsTotal * (5/6);

Here is a general function that takes the original array of values (vals), the index of the fixed value (fixedIndex), and the new sum (newSum); and returns a new array with suitably modified values:
function calc(vals, fixedIndex, newSum) {
var initSum = vals.reduce(function (prev, cur) {return prev + cur;}, 0);
var fixedElement = vals[fixedIndex];
var initRemainingSum = initSum - fixedElement;
var endRemainingSum = newSum - fixedElement;
return vals.map(function(cur, index) {return index === fixedIndex ? cur : endRemainingSum*(cur/initRemainingSum);})
}
For example:
calc([100, 225, 500], 1, 600)
returns:
[ 62.5, 225, 312.5 ]
[EDITED]
To answer your follow-on question in the comments, if you want to specify an array of fixed indices (fixedIndices), this should work:
function calc2(vals, fixedIndices, newSum) {
var initSum = vals.reduce(function (prev, cur) {return prev + cur;}, 0);
var fixedSum = fixedIndices.reduce(function (prev, cur, index) {return prev + vals[cur];}, 0);
var initRemainingSum = initSum - fixedSum;
var endRemainingSum = newSum - fixedSum;
return vals.map(function(cur, index) {return fixedIndices.indexOf(index) === -1 ? endRemainingSum*(cur/initRemainingSum) : cur;})
}
For example:
calc2([100, 225, 500], [1,2], 600)
returns:
[ -125, 225, 500 ]

I believe this is what you seeking for.
var elements = [100, 300, 225, 560, 900],newElements=[];
var containerSum = elements.reduce(function(prev, cur) {
return prev + cur;
});
var newContainerSum = 1500;
var indexToBeFixed = 1;
var remainingElementsTotal = newContainerSum - elements[indexToBeFixed];
for (var i = 0; i < elements.length; i++) {
newElements.push(i !== indexToBeFixed?(elements[i] * remainingElementsTotal) / (containerSum - elements[indexToBeFixed]):elements[i] );
}
console.log(newElements);
/*
[ 67.22689075630252,
300,
151.26050420168067,
376.47058823529414,
605.0420168067227 ]
*/
Update
elements array will be modified.

Related

Split an array into even chunks based on integer in javascript

This might be a duplicate, though I didn't find any questions specific to my problem here.
Say I have an array like this
var hundred = [1,2,3,4,5...100]
This array has 100 elements. From 1 to 100.
Based on an integer, how can I split this array into another array with the same amount of elements, except they've been evenly distributed like this?
var integer = 2;
var hundred = [50,50,50,50,50,50...100,100,100,100,100,100]
In this example, the array has 50 elements with the value 50, and 50 elements with the value 100, because the integer was 2.
I'm bad at math, so this might be incorrect, but I hope you understand what I mean. The array must have the same ammount of indexes after the calculation.
Edit (Due to me being very bad at formulating questions, I'm going to use the code I need this for here):
So I have a frequencybin array (from the AudioContext analyser):
var fbc_array = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteFrequencyData(fbc_array);
This array has a set number of elements ( They are the frequencies of audio played ).
Now I have a spectrum analyser, which has a set number of "bars" so if I have only 3 bars, then how can I split the fbc_array so that each bar has the evenly distributed frequency in it? For example, with 3 bars, bar one would have the bass, bar two would have the mids, bar three would have the treble.
I'm using a for loop for iterating over each bar:
for (i = 0; i < bars; i++) {
bar_x = i * canspace;
bar_width = 2;
bar_height = -3 - (fbc_array[i] / 2);
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height);
}
Here's what I gathered from this craziness! Sorry you're having trouble conveying your problem. That's always a headache! Good luck.
//set integer to whatever you want
var integer = 3;
var randomNumber;
var output = new Array()
function getRandomIntInclusive(min, max) {
randomNumber = Math.floor(Math.random() * (max - min + 1)) + min;
}
for(i = 0; i<integer;i++){
getRandomIntInclusive(1,100);
for(j = 1; j< (100/integer); j++){
output.push(randomNumber);
}
}
//note, you will not always get 100 array items
//you can check with console.log(output.length);
console.log(output);
(Written before your update, so guessing here).
You're looking for a way to approximate a graph so that it's divided into bands and each point within a band is replaced with that band's maximum:
Number.prototype.times = function(fn) {
var a = [];
for(var i = 0; i < this; i++)
a.push(fn(i));
return a;
}
function approximate(src, n) {
var res = [],
size = Math.ceil(src.length / n),
i = 0;
while(i < src.length) {
var chunk = src.slice(i, i += size)
var p = Math.max.apply(null, chunk);
// this gives you an average instead of maximum
// p = chunk.reduce((x, y) => x + y) / chunk.length;
res = res.concat(size.times(i => p));
}
return res;
}
src = 20..times(i => 10 + Math.floor(Math.random() * 80));
res = approximate(src, 4);
document.write('<pre>'+JSON.stringify(src));
document.write('<pre>'+JSON.stringify(res));

Get max and min of object values from JavaScript array

What is the best way to get the maximum and minimum values from a JavaScript array of objects?
Given:
var a = [{x:1,y:0},{x:-1,y:10},{x:12,y:20},{x:61,y:10}];
var minX = Infinity, maxX = -Infinity;
for( var x in a ){
if( minX > a[x].x )
minX = a[x].x;
if( maxX < a[x].x )
maxX = a[x].x;
}
Seems a bit clumsy. Is there a more elegant way, perhaps using dojo?
It won't be more efficient, but just for grins:
var minX = Math.min.apply(Math, a.map(function(val) { return val.x; }));
var maxX = Math.max.apply(Math, a.map(function(val) { return val.x; }));
Or if you're willing to have three lines of code:
var xVals = a.map(function(val) { return val.x; });
var minX = Math.min.apply(Math, xVals);
var maxX = Math.max.apply(Math, xVals);
Use this example
var lowest = Number.POSITIVE_INFINITY;
var highest = Number.NEGATIVE_INFINITY;
var tmp;
for (var i=myArray.length-1; i>=0; i--) {
tmp = myArray[i].Cost;
if (tmp < lowest) lowest = tmp;
if (tmp > highest) highest = tmp;
}
console.log(highest, lowest);
You could use sort. This method modifies the original array, so you might need to clone it :
var b = [].concat(a); // clones "a"
b.sort(function (a, b) { return a.x - b.x; });
var min = b[0];
var max = b[b.length - 1];
I know its a little too late, but for newer users you could use lodash. It makes the stuff a lot simpler.
var a = [{x:1,y:0},{x:-1,y:10},{x:12,y:20},{x:61,y:10}];
var X = [];
var Y = [];
a.map(function (val) {
X.push(val.x);
Y.push(val.y);
});
var minX = _.min(X);
var minY = _.min(Y);
var maxX = _.max(X);
var maxY = _.max(Y);
Or you could use .sort() to the task as procrastinator explained.
Another idea is to calculate max/min by reducing the values to one value. This is exactly same as your version in terms of time complexity but a bit different way to think. (reduce() is supported since JavaScript 1.8.)
var getMax = function (field) {
return a.reduce(function (acc, c) {
return Math.max(c[field], acc);
}, -Infinity);
}
var getMin = function (field) {
return a.reduce(function (acc, c) {
return Math.min(c[field], acc);
}, Infinity);
}
console.log(getMax('x')) //61
console.log(getMin('x')) //-1
console.log(getMax('y')) //20
console.log(getMin('y')) //0
You can use map functionality, but it is pretty much just a syntactic sugar around for. Any solution using reduce would be twice as slow as your "naive" because it would iterate array once for min value and once more for max. Your current solution is pretty much the best you can have in terms of performance. All you can do is to shave off some more lookups by caching them.

Access elements of a list using JQuery

I'm completely new to JQuery and I hope to get some help from SO folks.
This snippet basically generated a random numbers and filled a list along with index values
i.e. [0 10],[1 12],[2 30]... so on
function getRandomData() {
if (data.length > 0)
data = data.slice(1);
// do a random walk
while (data.length < totalPoints) {
var prev = data.length > 0 ? data[data.length - 1] : 50;
var y = prev + Math.random() * 10 - 5;
if (y < 0)
y = 0;
if (y > 100)
y = 100;
data.push(y);
}
// zip the generated y values with the x values
var res = [];
for (var i = 0; i < data.length; ++i)
res.push([i, data[i]])
return res;
}
Can any one out there help me out with the syntax to retrieve the elements inside data
which is in turn present in the res collection.
i.e. i want to know the random number generated each time the function getRandomData
is called
I hope i made it clear
Regards
Something like that?
// Save the return value of the function in a variable
var arr = getRandomData();
// Print data to the console
console.log(arr)
// Print the first dataset
console.log(arr[0]) // [0, 29]
// Print only the number of the first set
console.log(arr[0][1])
Do you mean something like this?
var res = [
[0, 10],
[1, 12],
[2, 30]
];
var x = res[0][1]; // returns 10
var y = res[1][1]; // returns 12
var z = res[2][1]; // returns 30
You can access any sub-arrays using this syntax:
array[first level index][second level index][...nth level index];
The data var appears to come from outside the function scope so you could just do
console.log(data)
Though I guess you're maybe asking for the syntax as given by #MildlyInteresting ?

Why doesn't this javascript work in browser?

I have the following code in a .js file:
$.extend(KhanUtil, {
// takes a number and returns the sign of that number
steveSign: function(num){
num = parseFloat(num)
if (num>=0){return 1}
else{return -1}
},
// takes a function, a lower bound for a zero,an upper bound for a zero, and locates
// that zero by iteratively halving the interval.
steveRoot: function(f,xmin,xmax){
var l = xmin
var r = xmax
var z = 0
for (i=0;i<6;i++){
z = (l + r)/2
if (KhanUtil.steveSign(f(l)) === KhanUtil.steveSign(f(z))){ l = z}
else{r = z}
}
return z
},
});
In my html file I define var f = function(x){return x**2 - 2} and run steveRoot(f,1,2), but my browser craps out. Why is this happening?
EDIT:
I am posting the entirety of my code, because it was requested in the comments. thanks a bunch for trying to help me out guys. The weird thing is the code runs fine 9 times out of ten. It is just occasionally that it "craps out". There are a lot of random variables in here, but I can't imagine why steveRoot would care about getting a slightly different function. The code works totally fine and never craps out when I don't include a variable which calls steveRoot.
The HTML file:
<!DOCTYPE html>
<html data-require="math graphie graphie-helpers play polynomials steveMath">
<head>
<title>Piecewise-defined function</title>
<script src="../khan-exercise.js"></script>
</head>
<body>
<div class="exercise">
<div class="vars">
<var id = "n">randRange(2,4)</var>
<var id = "abscissas">makeXList()</var>
<var id = "ordinates">makeYList(-9,9,abscissas.length)</var>
<var id = "points">makeCoordinates(abscissas,ordinates)</var>
<var id = "f">(function(x){return niceFunction(x,points)})</var>
<var id = zeros>steveRoot(f,-10,10)</var>
</div>
<div class="problems">
<div id="problem-type-or-description">
<p class="problem">You are going to have to answer 5</p>
<p class="question">Answer 5</p>
<div class="graphie" id="grid">
graphInit({
range: 10,
scale: 20,
tickStep: 1,
axisArrows: "<->"
});
a =style({
stroke: "red",
strokeWidth: 2
}, function() {
plot( function( x ) { return niceFunction(x,points);
}, [ -10, 10 ] );
});;
a.plot();
</div>
<p class="solution">5</p>
</div>
</div>
<div class="hints">
<!-- Any hints to show to the student. -->
</div>
</div>
</body>
The .js file:
$.extend(KhanUtil, {
//randomLines is a piecewise linear function in x, where the partition points are given by list_of_points.
//list_of_points is an array of arrays, for example [[1,5],[2,-1],[3,4]] would indicate the points (1,5), (2,-1), and (3,4)
//are on the curve. The points must be arranged in order of increasing abscissa.
randomLines: function(x,list_of_points)
{
for (i=0;i<list_of_points.length-1;i++)
{
var x_1 = list_of_points[i][0]
var y_1 = list_of_points[i][1]
var x_2 = list_of_points[i+1][0]
var y_2 = list_of_points[i+1][1]
var m = (y_2-y_1)/(x_2-x_1)
var y = m*(x - x_1) + y_1
if (x > x_1 && x <= x_2){return y}
}
if (x<=list_of_points[0][0]){return 0}
if (x>list_of_points[list_of_points.length-1][0]){return 0}
},
//randomLinesFunc: function(list_of_points){
// var f = function(x){
// return randomLines(x,list_of_points)
// }
//
// return f
//},
numInt: function(f,x){
var delta = .01
var sum = 0
var i = 0
while ((delta*i-10)<=x)
{sum = sum+delta*f(-10+i*delta)
i++
}
return sum
},
peace: function(x){return 2},
////////////////////////////////////////////////
//randRangeNZCU takes (min,max,n) and returns an array of nonzero numbers between max and min
//with successive numbers being distinct. For example [-1,2,-1] could show up, but [2,2,5] will not.
// NZCU stands for NonZeroConsecutiveUnique.
randRangeNZCU: function(min,max,n){
excluded = [0]
array = [KhanUtil.randRangeExclude(min,max,excluded)]
for (i=1;i<n;i++){
excluded = [0,array[i-1]]
array.push(KhanUtil.randRangeExclude(min,max,excluded))
}
return array
},
// makeCoordinates takes two arrays of the same length and returns the array of ordered pairs.
// Example: makeCoordinates([1,2,3],[4,5,6]) = [[1,4],[2,5],[3,6]]
makeCoordinates: function(array1,array2){
array = []
for (i=0;i<array1.length;i++){
array.push([array1[i],array2[i]])
}
return array
},
steveCubic: function(x){return -Math.pow(x,3)/2+3*x/2},
//niceFunction is a C^1 function which connects the points in "points". It is designed to be used
//in my "curveSketchingIntuition" exercise. Every point in the list will have 0 slope, except the first and last point.
niceFunction: function(x,points){
len = points.length
var x1 = points[0][0]
var x2 = points[1][0]
var y1 = points[0][1]
var y2 = points[1][1]
var k = (y1 - y2)/Math.pow(x1-x2,2)
if (x<x2){return k*Math.pow(x-x2,2)+y2}
for (i=1;i<len-2;i++){
var x1 = points[i][0]
var x2 = points[i+1][0]
var y1 = points[i][1]
var y2 = points[i+1][1]
xNew = (x-x1)*2/(x2-x1)-1
yNew = (KhanUtil.steveCubic(xNew)+1)*(y2-y1)/2+y1
if (x>=x1 && x<x2){return yNew}
}
var x1 = points[len-2][0]
var x2 = points[len-1][0]
var y1 = points[len-2][1]
var y2 = points[len-1][1]
var k = (y2 - y1)/Math.pow(x1-x2,2)
if (x>=x1){return k*Math.pow(x-x1,2)+y1}
},
makeXList: function(){
array = [-10]
i=0
while(array[i]<10){
x = array[i]+3*KhanUtil.randRange(1,3)
if (x<10){array.push(x)}
i=i+1
}
array.push(10)
return array
},
makeYList:function(min,max,n){
excluded = [0]
array = [KhanUtil.randRangeExclude(min,max,excluded)]
excluded.push(array[0])
array.push[KhanUtil.randRangeExclude(min,max,excluded)]
excluded = [0]
for (i=1;i<n;i++){
if (array[i-2]<array[i-1]){
array.push(KhanUtil.randRangeExclude(min,array[i-1]-1,excluded))
}
else{array.push(KhanUtil.randRangeExclude(array[i-1]+1,max,excluded))}
}
return array
},
newtonRoot: function(f,a){
var z = a
var m = (f(z+.01)-f(z-.01))/.02
for(i=0;i<2;i++){
z = z-f(z)/m
m = (f(z+.01)-f(z-.01))/.02
}
return z
},
steveSign: function(num){
num = parseFloat(num)
if (num>=0){return 1}
else{return -1}
},
steveRoot: function(f,xmin,xmax){
var l = xmin
var r = xmax
var z = 0
for (i=0;i<6;i++){
z = (l + r)/2
if (KhanUtil.steveSign(f(l)) === KhanUtil.steveSign(f(z))){ l = z}
else{r = z}
}
return z
},
locateZeros: function(f,points){
var len = points.length
var list = []
for(i=0;i<len-1;i++){
var x0 = points[i][0]
var x1 = points[i+1][0]
var y0 = points[i][1]
var y1 = points[i+1][1]
// var m = (y1-y0)/(x1-x0)
// var a = -y0/m+x0
// var z = KhanUtil.steveRoot(f,1,2)
list.push(KhanUtil.steveSign(f(x0)))
}
return list
},
});
In javascript x**2 is not valid. (SyntaxError: Unexpected token *)
You need to run KhanUtil.steveRoot(f,1,2); not just steveRoot(f,1,2);.

calculate array based on 100 max

Say I have a JS array like so...
var newArray = [20,182,757,85,433,209,57,828,635];
And I want to use this data to create a bar graph, where the height of the highest bar would == 100.
So, the 828 value bar needs to be set to 100, and the rest of the bars need to be calculated relative to that, and also to the closest integer. I am not sure how to go about this?
Is there a way to create a new array from the one above using a loop? Then I can use the new array?
First, calculate the max value:
var max = Math.max.apply(Math, newArray.map(Math.abs));
// will do `Math.max(300, 20, 182, ...)`
// if `newArray` is `[-300, 20, 182]`
Then, divide each element by that value, do it times 100, and round it down so that the highest value becomes 100:
var normalized = newArray.map(function(v) {
return Math.round(v / max * 100);
});
.map is essentially a loop, but the loop is done internally so you can write cleaner code. Do note it's ES5, so you need a shim for older browsers.
I like pimvdb's solution that uses no visible loops, but since you asked about loops, here's the loop-oriented way of doing it:
var newArray = [20,182,757,85,433,209,57,828,635];
var max = newArray[0];
var scaledArray = [];
// find max value
for (var i = 1; i < newArray.length; i++) {
if (newArray[i] > max) {
max = newArray[i];
}
}
// create new scaled array (integer values from 0 to 100)
for (i = 0; i < newArray.length; i++) {
scaledArray.push(Math.round(newArray[i] * 100 / max));
}
Working example: http://jsfiddle.net/jfriend00/ExWn8/
var max = newArray[0];
//determine max value
for (var i in newArray)
if (newArray[i] > max) max = newArray[i];
//count coficients for every bar
var coefficients = [];
for (var i in newArray)
coefficients[i] = Math.round(newArray[i] / max * 100);

Categories