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.
Related
With my very poor js knowledge, I am trying to solve the powerSum algorithm.Where I am supposed to return the count of the ways a number X can be expressed as the sum of the Nth powers of unique, natural numbers...
I have -somehow- got to the point where I can see my subsets printed out on the console but I haven't been able to figure out how to concatenate the result of my 'subsetSum' function to my 'subsets' variable so I can return my result as an array of arrays. The only way I get to have any returning value is if I concat my subsets into a STRING. and that is not what I am expecting. Here is my code.
// returns an array with all the results of natural numbers elevated
//to the nth power <= X
function powersLessThan(x,power){
let newArr = [];
for(var i = 1; i < x; i+=1){
var powered = Math.pow(i,power);
if (powered <= x){
newArr.push(powered);
}else if (powered > x){
break;
}
}
return newArr;
}
// returns an array of all the possible combinations of numbers that sum to X
function subsetsSum(numbersArr,target,partialSum){
var sum,n,remaining;
var subsets = [];
partialSum = partialSum || [];
sum = partialSum.reduce(function (a,b){
return a + b;
},0);
if (sum === target){
return partialSum; // this is my base case. datatype = object. Not sure why... ??
}
for (var i = 0; i < numbersArr.length; i+=1){
n = numbersArr[i];
remaining = numbersArr.slice( i + 1);
subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
}
return subsets;
}
console.log(subsetsSum(powersLessThan(100,2),100)); // with this my ooutput
is ' 1,9,16,25,4936,64100' instead of => [[1,9,16,25,49],[64,36],[100]] :/
The final count will be the length of the array above .. when it works..
Thanks for your help.
Change:
return partialSum;
To:
return [partialSum];
And change:
subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
To:
subsets = subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
(You could also just use, subsets.push(...))
I have the below array
["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2" ]
i want the output as ["5,p1","10,p2","5,p3"] , so p1..3 are video files paying time with start and end time . 0,5 mean p1 profile played for 5 sec and so on.
I want to know what profile take what time in total using ECMA script map,reduce function. Here is what i tried but it doesnt work:
var ca = uniqueArray.reduce(function(pval, elem) {
var spl = elem.split(',');
var difference = Math.round(spl[1] - spl[0]);
return difference;
},elem.split(',')[3]);
I dont think it can be done in one pass, but I could be wrong. I'd go for a 2 step...
Reduce the array to get unique map of pX values
Map the result back to an array in the required format
var input = ["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2" ]
var step1 = input.reduce(function(p,c){
var parts = c.split(",");
if(!p[parts[2]])
p[parts[2]] = 0;
p[parts[2]] += parseInt(parts[1],10) - parseInt(parts[0],10);
return p;
},{});
var result = Object.keys(step1).map(function(e){
return step1[e] + "," + e;
});
console.log(result);
You could use es6 map:
arrayWithNumbers.map(a => {var spl = a.split(','); return (spl[1] - spl[0]) + "," + spl[2]})
For a single loop approach, you could use a hash table for same third parts, like 'p1'. If a hash is given, then update the value with the actual delta.
var array = ["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2"],
hash = Object.create(null),
result = array.reduce(function(r, a) {
var parts = a.split(','),
delta = parts[1] - parts[0],
key = parts[2];
if (!(key in hash)) {
hash[key] = r.push([delta, key].join()) - 1;
return r;
}
r[hash[key]] = [+r[hash[key]].split(',')[0] + delta, key].join();
return r;
}, []);
console.log(result);
I have updated the code. Please check now.
var ca = ["0,5,p1", "24,29,p2", "78,83,p2", "78,83,p3", "162,167,p2" ] .reduce(function(result, elem) {
var spl = elem.split(',');
var difference = Math.round(spl[1] - spl[0]);
var found = false
for (var i = 0 ; i < result.length; i++) {
if (result[i].split(',')[1] == spl[2]) {
result[i] = parseInt(result[i].split(',')[0]) + difference+","+spl[2];
found = true;
}
}
if (!found) result.push(difference+","+spl[2]);
return result;
},[]);
console.log("modified array",ca);
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.
hey guys i wrote a function that compares array values and returns the minimum value but i want to know if there are ways to make it more efficient like iterating through all arrays (using one loop) and putting the results in a new array or making individual arrays sub-arrays of a single array, etc. Also the function provides the correct output but prints the answer three times:
var nums1 = [-7528819, 3927361, -6398192];
var nums2 = [1777100, -2299720, -5566643];
var nums3 = [7188445, 3724971, 7699332];
var nums4 = [-8432528, -159836, -1604959];
var nums5 = [2764889, 4681472, 701396];
var nums6 = [-5073513, 599535, 4388457];
var nums7 = [8689640, 8028586, 1022322];
var nums8 = [-1088592, 1211232, -7868192];
var nums9 = [-5848613, -4945165, 631213];
var nums10 = [3218429, -833619, -1495854];
var nums11 = [8007060, 1637562, -7568493];
var nums12 = [-8391131, -6585338, 131787];
var nums13 = [-3957775, -9396892, -6143241];
var nums14 = [-6258442, -7829421, 3696922];
var nums15 = [2136598, 4935467, -1621605];
var nums16 = [-7162005, 9861954, 8977930];
var nums17 = [7226452, 8551594, 7006517];
var nums18 = [-1751226, -2536997, -1782251];
var nums19 = [380582, 1614389, 3272584];
var nums20 = [-8988205, -5167181, -7561034];
var nums21 = [-484059, -7160121, 4076528];
var nums22 = [1947448, -5551253, 7491190];
var numsLength = nums1.length;
var i = 0;
var minNum;
function test(arr) {
for (i; i < numsLength; i++) {
if (arr[0] < arr[1] && arr[2]) {
minNum = arr[0];
} else if (arr[1] < arr[2] && arr[0]) {
minNum = arr[1];
} else if (arr[2] < arr[1] && arr[0]) {
minNum = arr[2];
}
console.log(minNum);
}
}
test(nums1);
You could just use Math.min function.
console.log(Math.min.apply(null, nums1));
Look at his snippet of code and read inline comments:
var nums = [];
// I'm pushing only 3 sets of data, but there can be any number
// Also there can be any number of elements in each array as you can see
nums.push([-7528819, 3927361, -6398192]);
nums.push([1777100, -2299720, -5566643, 380582]);
nums.push([7188445, 3724971, 7699332, 1947448, -5551253, 7491190]);
function produceResults(nums) {
var i,
results = [];
// gathering results
for (i = 0; i < nums.length; i++) {
results.push(Math.min.apply(null, nums[i]));
}
return results;
}
console.log(produceResults(nums));
So 2 suggestions:
use more dynamic structure (array of arrays) instead of
defining 22 arrays.
use built in JS functions and components (Math.min)
Unrolling a loop is actually the most efficient implementation of a loop in most cases. However, practically speaking, unrolling a loop isn't usually feasible. With a small, fixed-size array, like those you have here, each permutation of the loop is obvious, and if your goal is raw speed you can't get much more efficient than what you have. That being said, the loop in your function is useless, as others have pointed out., because you've essentially unrolled the loop already. Also the syntax of the if statement is incorrect, and you are not handling the case where values in the array are equal. For fixed arrays of size three you want something more along the lines of...
if (val1 <= val2 && val1 <= val3) {
minVal = val1;
} else if (val2 <= val1 && val2 <= val3) {
minVal = val2;
} else minVal = val3;
Now if you want to do an arbitrary search for the min value of any size array you would do something similar, but using a loop, like...
var minVal = null;
for (var i = 0; i < arr.length; i++) {
if (minVal === null || minVal > (val = arr[i]))
minVal = val;
}
Depending on what you actually want to accomplish, and the size of the array, it might make sense to sort the array and rerurn the min (0 index) from the sorted array. If you go that route, start with a google search for "sort algorithms"
This question already has answers here:
How to find the sum of an array of numbers
(59 answers)
Closed 7 years ago.
I have an array containing some values and I want to get their sum. Here is the example:
var somearray = ["20","40","80","400"];
I want to sum these values using jQuery. In this example the result would be 540.
To also handle floating point numbers:
(Older) JavaScript:
var arr = ["20.0","40.1","80.2","400.3"],
n = arr.length,
sum = 0;
while(n--)
sum += parseFloat(arr[n]) || 0;
ECMA 5.1/6:
var arr = ["20.0","40.1","80.2","400.3"],
sum = 0;
arr.forEach(function(num){sum+=parseFloat(num) || 0;});
ES6:
var sum = ["20.0","40.1","80.2","400.3"].reduce((pv,cv)=>{
return pv + (parseFloat(cv)||0);
},0);
The reduce() is available in older ECMAScript versions, the arrow function is what makes this ES6-specific.
I'm passing in 0 as the first pv value, so I don't need parseFloat around it — it'll always hold the previous sum, which will always be numeric. Because the current value, cv, can be non-numeric (NaN), we use ||0 on it to skip that value in the array. This is terrific if you want to break up a sentence and get the sum of the numbers in it. Here's a more detailed example:
let num_of_fruits = `
This is a sentence where 1.25 values are oranges
and 2.5 values are apples. How many fruits are
there?
`.split(/\s/g).reduce((p,c)=>p+(parseFloat(c)||0), 0);
// num_of_fruits == 3.75
jQuery:
var arr = ["20.0","40.1","80.2","400.3"],
sum = 0;
$.each(arr,function(){sum+=parseFloat(this) || 0;});
What the above gets you:
ability to input any kind of value into the array; number or numeric string(123 or "123"), floating point string or number ("123.4" or 123.4), or even text (abc)
only adds the valid numbers and/or numeric strings, neglecting any bare text (eg [1,'a','2'] sums to 3)
You don't need jQuery. You can do this using a for loop:
var total = 0;
for (var i = 0; i < someArray.length; i++) {
total += someArray[i] << 0;
}
Related:
How to find the sum of an array of numbers
You can use reduce which works in all browser except IE8 and lower.
["20","40","80","400"].reduce(function(a, b) {
return parseInt(a, 10) + parseInt(b, 10);
})
Another method, if eval is safe & fast :
eval(["10","20","30","40","50"].join("+"))
If you want it to be a jquery method, you can do it like this :
$.sum = function(arr) {
var r = 0;
$.each(arr, function(i, v) {
r += +v;
});
return r;
}
and call it like this :
var sum = $.sum(["20", "40", "80", "400"]);
var total = 0;
$.each(someArray,function() {
total += parseInt(this, 10);
});
In http://bugs.jquery.com/ticket/1886 it becomes obvious that the jQuery devs have serious mental issues reg. functional programming inspired additions. Somehow it's good to have some fundamental things (like map) but not others (like reduce), unless it reduces jQuery's overall filesize. Go figure.
Helpfully, someone placed code to use the normal reduce function for jQuery arrays:
$.fn.reduce = [].reduce;
Now we can use a simple reduce function to create a summation:
//where X is a jQuery array
X.reduce(function(a,b){ return a + b; });
// (change "a" into parseFloat("a") if the first a is a string)
Lastly, as some older browsers hadn't yet implemented reduce, a polyfill can be taken from MDN (it's big but I guess it has the exact same behavior, which is desirable):
if ( 'function' !== typeof Array.prototype.reduce ) {
Array.prototype.reduce = function( callback /*, initialValue*/ ) {
'use strict';
if ( null === this || 'undefined' === typeof this ) {
throw new TypeError(
'Array.prototype.reduce called on null or undefined' );
}
if ( 'function' !== typeof callback ) {
throw new TypeError( callback + ' is not a function' );
}
var t = Object( this ), len = t.length >>> 0, k = 0, value;
if ( arguments.length >= 2 ) {
value = arguments[1];
} else {
while ( k < len && ! k in t ) k++;
if ( k >= len )
throw new TypeError('Reduce of empty array with no initial value');
value = t[ k++ ];
}
for ( ; k < len ; k++ ) {
if ( k in t ) {
value = callback( value, t[k], k, t );
}
}
return value;
};
}
You can do it in this way.
var somearray = ["20","40","80","400"];
somearray = somearray.map(Number);
var total = somearray.reduce(function(a,b){ return a+b },0)
console.log(total);
var arr = ["20.0","40.1","80.2","400.3"],
sum = 0;
$.each(arr,function(){sum+=parseFloat(this) || 0; });
Worked perfectly for what i needed. Thanks vol7ron