Convert a range of numbers to portion of 100 - javascript

I have a list of numbers (any length) ranging from 0 - 100, including duplicates. I need convert those numbers to portions of 100.
For example:
[25, 50] becomes [33.333, 66.666]
[25, 50, 50] becomes [20, 40, 40]
What algorithm would work best for this?

You would need to calculate the sum of the values in your array - then you could divide each value in your array by that sum, and multiply by 100.

Try this :
console.log(33.333 - 33.333 % 25); // 50
% is MODULO operator.
Number.prototype.range = function(a) {
return this - this % a;
}
console.log((33.333).range(25)); // 25;
console.log((66.666).range(25)); // 50;
In array use map like this :
console.log([33.333, 66.666].map(function(a) {
return a.range(25);
}));
Demo

This can be done by calculating the sum of the array and then dividing each value by that. It can be done easily using Array.reduce to sum and Array.map to create a new array with the final output. Here is an example:
var arr1 = [25, 50];
var arr2 = [25, 50, 50];
function proportion(arr) {
var sum = arr.reduce(function(prev, cur){
return prev + cur;
});
var result = arr.map(function(val){
return (val/sum)*100;
});
return result;
}
console.log(proportion(arr1)); // [33.33333333333333, 66.66666666666666]
console.log(proportion(arr2)); // [20, 40, 40]
JSBin here: http://jsbin.com/texuc/1/edit

The simplest way to solve this is to sum the array, find each value as a fraction of that sum, and then multiply by 100.
This code should do the trick.
var inputArray = [25, 50, 50];
var outputArray = [];
var total = 0;
for (var i=0; i<(inputArray.length); i++) {
total += inputArray[i];
}
for (var i=0; i<(inputArray.length); i++) {
outputArray[i] = ((inputArray[i])/total) * 100;
}

Related

How to calculate the sum and product of each element of multiple arrays?

Please bear with me this is difficult to explain. I will first explain how to do it successfully with only one set of data.
First, say I have an array like so yValuesMinusMean = [-5, -4, -1, 10]
I have another array like so xValuesMinusMean = [ 2.75,3.75,6.75,5.75 ]
Both of the above arrays can have numerous values. However, the length of both arrays is the same. So if the first one has 4, then the second one will definitely have 4.
I want to calculate the sum and product of the arrays. This is what I mean:
var sumOfXTimesYValues = this.calculateProductAndSum(yValuesMinusMean, xValuesMinusMean);
calculateProductAndSum(yValuesMinusMean = [], xValuesMinusMean = []) {
let total = 0;
for(let i = 0; i < yValuesMinusMean.length; i++) {
let product = (yValuesMinusMean[i] * xValuesMinusMean[i]);
total += product;
};
return total;
},
The result of this: console.log('sumOfXTimesYValues', sumOfXTimesYValues); is
17
LOGIC : (-5 * 2.75) + (-4 * 3.75) + (-1 * 6.75) + (10 * 5.25) = 17
So far, everything works. However, I want to make it so that instead of xValuesMinusMean being a single array with multiple numerical values, it will be a single array containing multiple arrays, with each array having the same number of elements as in yValuesMinusMean. Like so:
xValuesMinusMean = [ [ 2.75,3.75,6.75,5.75 ], [-2,-1,2,1]. .... ]
END GOAL: sumOfXTimesYValues = [17, 22, ...]
Logic for the second array item: (-5 * -2) + (-4 * -1) + (-1 * 2) + (10 * 1) = 22
Essentially, you're multiplying each value in each array in xValuesMinusMean with a value in yValuesMinusMean in the same order. So, -5 is the 0th item in the yValuesMinusMean array, and -2 is the 0th item in the array within xValuesMinusMean. So -5 * -2.
My next steps would be to do something like this:
xValuesMinusMean.forEach(element => {
for(let i = 0; i < xValuesMinusMean.length; i++) {
let product = (newCategoryArray[i] * xValuesMinusMean[i]);
total += product;
};
});
However, it yields the following: sumOfXTimesYValues = 352, which isn't correct. How would I be able to achieve the end goal?
END GOAL: sumOfXTimesYValues = [17, 22, ...]
Create a generic function for computing a scalar product (you've already got it):
function scalarProduct(a, b) {
let res = 0;
for(let i = 0; i < a.length; i++) {
res += a[i] * b[i];
}
return res;
}
and then map it over your matrix (array of vectors):
result = xValuesMinusMean.map(vec => scalarProduct(vec, yValuesMinusMean))
You can have one reduce function where you will take product of arrays and store it in accumulator.
const val =[ [ 2.75,3.75,6.75,5.25 ], [-2,-1,2,1]];
const yvalues = [-5, -4, -1, 10];
console.log(val.map(o=>o.reduce((a,e,i)=>a+=e*yvalues[i],0)));
Looks like your calculation is not correct first set of arrays will also return 22.
Live Demo :
const yValuesMinusMean = [-5, -4, -1, 10];
const xValuesMinusMean = [[2.75, 3.75, 6.75, 5.75], [-2, -1, 2, 1]];
const finalArr = [];
xValuesMinusMean.forEach(arr => {
let cal = 0;
arr.forEach((item, index) => {
cal += item * yValuesMinusMean[index]
});
finalArr.push(cal);
});
console.log(finalArr); // [22, 22]

Finding max value in array (array.find)

Im learning Javascipt and actually im on episode with array methods.
My imaginary exercise relies on found the Max/Min value in array by array.find method.
Acutally I did smth like that, but script returned me "Undefined".
Please help. :)
const scores = [10, 20, 30, 22, 25, 109, 90];
const maxScore = scores.find(score => {
let max = 0;
for (let i=1; i < scores.length; i++){
if(score[i] > max){
max = score[i];
};
};
return max;
});
console.log(maxScore);
P.S. I know about "Math.max.apply", but I have to do it by array.find and simple loop.
You could take a closure over an index for looping from the end and a temporary max value which is at start undefined and gets the first value from the first element.
Then loop while the value at temp index is smaller than score, store this value in max, repeat.
At the end return the result if index plus one is equal to the temp index.
This approach takes a single loop. find iterates from start of the array and the inner loop from the end of the array if both indices cross, the result is found.
const
scores = [100, 20, 30, 22, 25, 109, 90],
maxScore = scores.find(
((j, max) => (score, i, array) => {
if (max === undefined) {
max = score;
j = array.length;
}
if (score < max) return;
while (array[j - 1] < score) max = array[--j];
return i + 1 === j;
})
()
);
console.log(maxScore);
The simplest way to do it, without using any Array methods, can be written as:
const maxScore = (scores) => {
let score = 0;
for ( let i = 0; i < scores.length; i++ ) {
if(scores[i] > score) {
score = scores[i]
}
}
return score;
}
From MDN:
The find() method returns the value of the first element
in the provided array that satisfies the provided testing function.
Lets redefine our simple function again,
const maxScore = scores => {
let score = Number.NEGATIVE_INFINITY;
scores.forEach(element => {
let acc = scores.find(number => number > score);
if(!isNaN(acc)) {
score = acc;
}
})
return score;
}
find works on each array element. So take the max outside the find method & log max. Besides there were two typos
const scores = [10, 20, 30, 22, 25, 109, 90];
let max = 0;
const maxScore = scores.find((score) => {
for (let i = 1; i < scores.length; i++) {
if (scores[i] > max) {
max = scores[i];
};
};
return max;
});
console.log(max)
Try this:
const scores = [10, 20, 30, 22, 25, 109, 90];
let max = 0;
scores.find(score => { if(score > max) max = score });
console.log(max);
Your current code is looping the scores array whilst its already looping it, JavaScripts .find, essentially loops the array.
const scores = [10, 20, 30, 22, 25, 109, 90];
scores.reduce(function(a,b) { return a > b ? a : b });
// 109

finding max in a array and their counterpart in javascript

I have two array with the same dimension, one for frequency, one for value.
Examples :
var value = [20, 40, 10, 80, 16];
var frequency = [10, 16, 25, 31.5, 40];
I used the method math.max in this way
var maxValue = Math.max.apply(Math, value);
Now I want to find the frequency in the same position of frequency array.
Assuming the values are unique.
var maxValue = Math.max.apply(Math, value);
var index = value.indexOf(maxValue);
var freq = frequency[index];
Just in O(n) time you can do as follows. This should be as efficient as a single Math.max() function.
var value = [20, 40, 10, 80, 16],
frequency = [10, 16, 25, 31.5, 40],
result = value.reduce((p,c,i) => c > p.v ? (p.v = c, p.f = frequency[i],p)
: p, {v:-Infinity, f:-Infinity});
console.log(result);
You can do:
var maxValue = Math.max.apply(Math, value); //finding max value
var index_freq = value.indexOf("maxValue "); // findind index of that max
var myFrequecy = frequency[index_freq]; //frequecy value for same as in value

JS - Thin number of points based on density

Say I have an array as follows (each small array is [x, y]):
var myPoints = [[25, 28], [26, 26], [70, 40], [50, 50], [300, 300], [285, 350], [1000, 1000]];
Let's say I need to thin the array down to 4 points. (this is a small example, my acutal array has thousands of points) How could I go about thinning the array based on density so more points are removed from areas with points closer together and less points are removed from areas with lower density?
In this case (reducing the above array from 8 to 4 items) I would expect the returned array to look something like the following:
var thinnedPoints = [[25, 28], [70, 40], [300, 300], [1000, 1000]];
My idea on how to approach this would be to generate a dictionary that maps the point to it's minimum distance to another point (e.g. a point close to another point would have a small minimum distance) then sort the dictionary based on ascending minimum distance, then remove every n'tn item of the dictionary.
The problem with this approach is I don't know how to efficiently generate the distance to closest other point value for each point.
Is there an efficient way to generate those values or maybe is there another way to approach this density based thinning problem?
Thanks!
It seems you want to solve either a P-center problem or a P-median problem.
From Approximability Results for the p-Center Problem by Stefan Buettcher,
The p-Center problem, also known as the Min-Max Multicenter problem
or the Facility Location problem, is a famous problem from operations
research. Informally, it is the problem of placing fire stations in a
city so that the maximum time to reach any point in the city is
minimized.
From Methods for Solving the p-Median Problem: An Annotated Bibliography by J. Reese,
The p-median problem is simply stated as: Given a graph or a network
G = (V, E), find Vp ⊆ V such that |Vp| = p, where p may either
be variable or fixed [...], and that the sum of the shortest distances
from the vertices in {V\Vp} to their nearest vertex in Vp is
minimized.
Both problems are NP-complete in general, so there is no (known) way to solve them in polynomial time. But there are various heuristics you could try.
A very simple and efficent solution that works especially well on large sets is to just pick the points randomly. This implicitly removes less points from regions containing less points than elsewhere - which seems to be just what you want, if you only want to scale the density linearly. It should yield the same results as your approach, without needing to calculate any distances.
If the data is not ordered in any way (i.e. already random), you can also drop every second point or just the first or second half.
If you want to tweak the density distribution non-linearly, you could divide the set into multiple regions (e.g. squares) small enough so that the density is roughly uniform in each of them, and then drop every n-th of the points per region. If you choose the region size appropriately, this approach might also deliver better (and more consisten) results than the purely random one on smaller data sets.
You can use for..of loop, for loop, .map(), Math.min(), .filter().
Loop through each element of array, assign x, y to separate array variables; subtract the difference between each element in x or y arrays; map original array, begin by removing first or second element of matched pair where the two elements have the least numeric difference between any other number in array; that is, the two numbers are separated by the least amount of digits. Continue removing elements, as distance between numbers increases, until n, here, 3, elements are removed from original array.
For example, mapping x can return either
[[25, 28], [70, 40], [300, 300], [1000, 1000]];
or
[[26,26], [50,50], [285,350], [1000,1000]]
as the range between the numbers is the same each in direction
[1, 1, 20, 20, 15, 15, 700]
var myPoints = [
[25, 28],
[26, 26],
[70, 40],
[50, 50],
[300, 300],
[285, 350],
[1000, 1000]
];
var [x, y] = [
[],
[]
];
var [xx, yy] = [
[],
[]
];
for (let z of myPoints) {
[x, y] = [
[...x, z[0]],
[...y, z[1]]
];
}
var stop = 3;
for (var i = 0; i < x.length; i++) {
var prop = x[i];
if (typeof xx[i] !== "object") {
xx[i] = {
index: i,
diff: [],
value: prop
};
}
for (var len = 0; len < x.length; len++) {
var key = x[len];
xx[i].diff.push(
prop > key
? prop - key
: key > prop ? key - prop : Infinity
)
}
}
var range = xx.map(prop => Math.min.apply(Math, prop.diff));
var temp = range.slice(0);
for (var i = 0; i < stop; i++) {
var curr = Math.min.apply(Math, temp);
var index = temp.indexOf(curr);
temp[index] = Infinity;
var pair = Math.min.apply(Math, temp);
var next = temp.indexOf(pair);
temp[next] = Infinity;
x[next] = void 0;
};
var res = myPoints.map((prop, index) =>
x[index] === undefined ? null : prop).filter(Boolean);
console.log(res);
usage as a function
var myPoints = [
[25, 28],
[26, 26],
[70, 40],
[50, 50],
[300, 300],
[285, 350],
[1000, 1000]
];
var filter = (arr, xy, n) => {
var [x, y] = [
[],
[]
];
var [xx, yy] = [
[],
[]
];
for (let z of arr) {
[x, y] = [
[...x, z[0]],
[...y, z[1]]
];
}
var XY = {
"x": [x, xx],
"y": [y, yy]
};
var item = XY[xy];
var stop = n;
for (var i = 0; i < item[0].length; i++) {
var prop = item[0][i];
if (!item[1][i]) {
item[1][i] = {
index: i,
diff: [],
value: prop
};
}
for (var len = 0; len < item[0].length; len++) {
var key = item[0][len];
item[1][i].diff.push(
prop > key ? prop - key : key > prop ? key - prop : Infinity
)
}
}
var range = item[1].map(prop => Math.min.apply(Math, prop.diff));
var temp = range.slice(0);
for (var i = 0; i < stop; i++) {
var curr = Math.min.apply(Math, temp);
var index = temp.indexOf(curr);
temp[index] = Infinity;
var pair = Math.min.apply(Math, temp);
var next = temp.indexOf(pair);
temp[next] = Infinity;
item[0][next] = void 0;
};
return arr.map((prop, index) =>
item[0][index] === undefined ? null : prop).filter(Boolean);
}
console.log(filter(myPoints, "x", 3));

How can I find all indexes of the max value of an array in javascript?

I am trying to find a way to get the max value of an array, then find all indexes of that value. I want to repeat this two more times.
I have an array of 8 scores. I want to find all first places, all second places, and all third places.
Array = [0, 400, 300, 400, 300, 200, 100, 200]
1st place indexes: 1, 3
2nd place indexes: 2, 4
3rd place indexes: 5, 7
How can I achieve this in javascript?
The following code does the trick:
var scores = [0, 400, 300, 400, 300, 200, 100, 200];
// make a working copy, so that we can change the working copy
// while doing the calculations without changing the original array
var working = scores.slice(0),
max,
indices,
numberOfPlaces = 3,
results = [];
for (var p = 0; p < numberOfPlaces; p++) {
max = Math.max.apply(null, working);
indices = [];
for (var i = 0; i < working.length; i++)
if (working[i] === max && working[i] > Number.NEGATIVE_INFINITY) {
indices.push(i);
working[i] = Number.NEGATIVE_INFINITY;
}
results.push(indices);
}
For your input results will be [[1,3], [2,4], [5,7]]. That is, results[0] will hold the first place indices, results[1] will hold the second place indices, and so on.
If you later decided you only wanted the first two places, or your wanted the first five, just change the numberOfPlaces variable.
Assuming the scores are not big numbers, you can build a hash of "score to indexes", and then sort by keys, and print out the indexes:
the running sample:
http://jsfiddle.net/nmA35/2/
the code:
var arr = [0, 400, 300, 400, 300, 200, 100, 200];
var hashValueToPosition = {};
var i;
for (i = 0; i < arr.length; i++) {
hashValueToPosition[arr[i]] = (hashValueToPosition[arr[i]] || []);
hashValueToPosition[arr[i]].push(i);
}
// see http://stackoverflow.com/questions/208016/how-to-list-the-properties-of-a-javascript-object for Object.keys or the following:
var getKeys = function(obj){
var keys = [];
for(var key in obj){
keys.push(key);
}
return keys;
}
var arrMaxToMinScores = getKeys(hashValueToPosition).sort().reverse();
for (i = 0; i < arrMaxToMinScores.length; i++) {
$("body").append("<pre>" + arrMaxToMinScores[i] + ": " + JSON.stringify(hashValueToPosition[arrMaxToMinScores[i]]) + "</pre>");
}
function awardPrizes(arr){
var L= arr.length, prizes= [[], [], []], n;
// save the three highest scores in scores array:
// eg: [400,300,200]
var scores= arr.slice().filter(function(n, i){
return arr.indexOf(n)== i;
}).sort(function(a, b){ return b-a}).slice(0, 3);
//put the high scoring indexes in the relevant prizes array:
arr.forEach(function(itm, i){
n= scores.indexOf(itm);
if(n!= -1) prizes[n].push(i);
});
return prizes;
//[first group,second group,third group]
}
var data= awardPrizes([0, 400, 300, 400, 300, 200, 100, 200]);
/* returned value: (Array)
[
[1, 3],
[2, 4],
[5, 7]
]
*/
Like functional programming?
a={};[0, 400, 300, 400, 300, 200, 100, 200].forEach(
(el,i) => a[el]? a[el].push(i) : a[el]=[i]
);
Object.keys(a).sort().reverse().map(k => [Number(k),a[k].sort()])
Basically hashes all the values, then goes through the keys in descending order, mentioning the indexes in ascending order. Ex:
[
[400,[1,3]],
[300,[2,4]],
[200,[5,7]],
[100,[6]],
[0,[0]]
]

Categories