Given an array of objects
function Example(x, y){
this.prop1 = x;
this.prop2 = y;
}
var exampleArray = new Array();
exampleArray.push(nex Example(0,1));
exampleArray.push(nex Example(1,3));
Now I would like to add a function which computes the average for one of the properties
function calcAvg(exampleArray, 'prop1') -> 0.5
function calcAvg(exampleArray, 'prop2') -> 2
If I don't want to use jQuery or other libraries, is there a generic way to do this?
Solution with Array.prototype.reduce method and check for valid property:
function Example(x, y) {
this.prop1 = x;
this.prop2 = y;
}
var exampleArray = new Array();
exampleArray.push(new Example(0, 1));
exampleArray.push(new Example(1, 3));
function calcAvg(arr, prop) {
if (typeof arr[0] === 'object' && !arr[0].hasOwnProperty(prop)) {
throw new Error(prop + " doesn't exist in objects within specified array!");
}
var avg = arr.reduce(function(prevObj, nextObj){
return prevObj[prop] + nextObj[prop];
});
return avg/arr.length;
}
console.log(calcAvg(exampleArray, 'prop2')); // output: 2
I think it will work ,
You need to iterate through all Example objects in the array and add the given property's value in a variable e.g. sum and then at the end divide it by total number of objects in the array to get average.
console.log(avg(exampleArray, 'prop1'));
function avg (array, propName){
var sum = 0;
array.forEach(function(exm){
sum+= exm[propName];
});
return sum / array.length;
}
You can use Array.prototype.reduce() for it.
The reduce() method applies a function against an accumulator and each value of the array (from left-to-right) to reduce it to a single value.
function Example(x, y) {
this.prop1 = x;
this.prop2 = y;
}
function calcAvg(array, key) {
return array.reduce(function (r, a) {
return r + a[key];
}, 0) / array.length;
}
var exampleArray = [new Example(0, 1), new Example(1, 3)],
avgProp1 = calcAvg(exampleArray, 'prop1'),
avgProp2 = calcAvg(exampleArray, 'prop2');
document.write(avgProp1 + '<br>');
document.write(avgProp2);
This code iterates over every value of arr, searches for property prop in every value, pushes the value of that property to an array named values and returns the sum of all the values in values divided by the number of values in it.
function calcAvg(arr,prop){
var values = [];
for(var i = 0; i<arr.length; i++){
values.push(arr[i][prop]);
}
var sum = values.reduce(function(prev,current){
return prev+current;
});
return sum/values.length;
}
Demo is here.
Related
This code returns only returns the order of the sums of the numeric value, how do I return the array element in a list arranged by largest sum on top?
For instance, the result should be:
"1234-2722-2343-2842"
"1234-2722-2343-2345"
"1234-2322-2343-2342"
Code:
var addSum = function(ccNum) {
var sum = 0;
for (var i=0; i<ccNum.length; i++ ) {
var eachLetter = ccNum.charAt(i);
if (!isNaN(eachLetter)) {
sum += +eachLetter;
}
}
return sum;
};
var ccNums = ["1234-2322-2343-2342","1234-2722-2343-2345", "1234-2722-2343-2842"];
var checkNums = [];
for (var i=0; i<ccNums.length; i++) {
var ccNum = ccNums[i];
var sum = addSum(ccNum);
console.log("The checksum of CC number:"+ccNum+" is "+sum);
checkNums.push(sum);
}
checkNums.sort(function(a,b) {
return b-a;
});
console.log(checkNums);
The solution using String.replace, String.split, Array.map, Array.filter and Array.reduce:
var ccNums = ["1234-2322-2343-2342","1234-2722-2343-2345", "1234-2722-2343-2842"],
getSum = function(num){
return num.replace("-", "").split("").map(Number).filter(Boolean).reduce(function(prev, next){
return prev + next;
});
};
ccNums.sort(function (a, b) {
return getSum(b) - getSum(a);
});
console.log(ccNums);
The output:
["1234-2722-2343-2842", "1234-2722-2343-2345", "1234-2322-2343-2342"]
I suggest use Sorting with map, because it uses only one iteration for the sum of a string and uses it until the sorts end. Then it rebuilds a new array with the sorted items.
var ccNums = ["1234-2322-2343-2342", "1234-2722-2343-2345", "1234-2722-2343-2842"];
// temporary array holds objects with position and sort-value
var mapped = ccNums.map(function (el, i) {
return {
index: i,
value: el.split('').reduce(function (r, a) { return r + (+a || 0); }, 0)
};
});
// sorting the mapped array containing the reduced values
mapped.sort(function (a, b) {
return b.value - a.value;
});
// container for the resulting order
var result = mapped.map(function (el) {
return ccNums[el.index];
});
console.log(result);
Use Array#sort with help of String#split and Array#reduce methods
var ccNums = ["1234-2322-2343-2342", "1234-2722-2343-2345", "1234-2722-2343-2842"];
// function to get sum of numbers in string
function sum(str) {
// split string
return str.split('-')
// iterate and get sum
.reduce(function(a, b) {
// parse string to convert to number
return a + Number(b); // in case string contains no-digit char that for avoiding NaN use "return a + ( parseInt(b, 10) || 0 )
}, 0); //set initial value to avoid 2 parsing
}
// call sort function
ccNums.sort(function(a, b) {
// find out sum and compare based on that
return sum(b) - sum(a);
});
console.log(ccNums)
Or much better way would be, store the sum in an object and refer in sort function which helps avoid calling sum function multiple times.
var ccNums = ["1234-2322-2343-2342", "1234-2722-2343-2345", "1234-2722-2343-2842"];
// function to get sum of numbers in string
function sum(str) {
// split string
return str.split('-')
// iterate and get sum
.reduce(function(a, b) {
// parse string to convert to number
return a + Number(b);
}, 0); //set initial value to avoid 2 parsing
}
var sumArr = {};
// create object for referncing sum,
// which helps to avoid calling sum function
// multiple tyms with same string
ccNums.forEach(function(v) {
sumArr[v] = sum(v);
});
// call sort function
ccNums.sort(function(a, b) {
// find out sum and compare based on that
return sumArr[b] - sumArr[a];
});
console.log(ccNums)
I want to filter out values for an array by passing another array to the filter function.
x = [1,2,3];
y = [2,3];
var n = x.filter(filterByArray);
function filterByArray(element, index, array, myOtherArray){
// some other code
});
What is the best way to pass "y" to the "myOtherArray" prototype in the function?
You can use the second parameter of .filter(callback[, thisArg]) to set its this value to something "useful" such as your second array
function filterByArray(element, index, array) {
return this.lookup.indexOf(element) > -1; // this.lookup == y
};
var x = [1,2,3],
y = [2,3];
var result = x.filter(filterByArray, {lookup: y});
console.log(result);
fiddle
You cannot change the signature of the callback but you can have a separate class that takes the other array as parameter:
function MyFilter(otherArray) {
this.otherArray = otherArray;
}
MyFilter.prototype.filterByArray = function(element, index, array) {
// you can use this.otherArray here
};
and then:
x = [1,2,3];
y = [2,3];
var myFilter = new MyFilter(y);
var n = x.filter(myFilter.filterByArray);
I want to make an 2D 4x4 array of coordinates (X, Y) that its position on the array holds null values. Like main_matrix[0][0] = null ... main_matrix[4, 4] = null but I can't figure how I make this.
I would appreciate this prototype because I want to remake an 2048.
Thanks in advance
You can make a function that creates an array and fills if with values, optionally using a callback, and use that to create the array of arrays:
function createArray(len, value) {
var a = new Array(len), f = typeof value == "function";
for (var i = 0; i < len; i++) a[i] = f ? value() : value;
return a;
}
var main_matrix = createArray(4, createArray.bind(this, 4, null));
main_matrix=[];
for(var i=0;i<4;i++){
main_matrix[i]=[];
for(var j=0;j<4;j++){
main_matrix[i][j]=null;
}
}
Use this implementation:
Array.apply(null, Array(2048)).map(function() { return Array.apply(null, Array(2048)).map(function() { return null }) });
Good luck
I'm trying to switch in general to functional programming and want to use underscore for JavaScript.
But I'm stuck at first base. I could not create an array at all and resorted to imperative language, and I can't seem to transform them properly either: n.length is correct, but n[0].length is undefined (see fiddle)
var a = new Array(5);
for (i = 0; i < a.length; i++) {
a[i] = new Array(6);
}
var n = _.map(a, function (row, rowIdx) {
_.map(row, function(col, colIdx) {
return rowIdx * colIdx
});
});
console.log(a.length)
console.log(n.length)
console.log(a[0].length);
console.log(n[0].length);
To "functionally" create a 5 x 6 matrix using underscore, you could do something like this:
var matrix = _.range(5).map(function (i) {
return _.range(6).map(function (j) {
return j * i;
});
});
The _.range function (documentation) is a shorthand for creating arrays that are filled with sequential numbers. For example, _.range(5) returns the array [0,1,2,3,4]. Ranges start at zero.
If you didn't want to use _.range, you could do this with raw JavaScript by using array literals:
var matrix = [0,1,2,3,4].map(function (i) {
return [0,1,2,3,4,5].map(function (j) {
return j * i;
});
});
Another way to create a matrix would be to use _.times:
var matrix = _.times(6, function(x){
return _.times(7, function(y){
// do whatever needs to be done to calculate the value at x,y
return x + ',' + y;
});
});
In ES6/2015
var range = num => Array.apply(null, Array(num)).map((i, n) => n);
var matrix2d = (a1, a2) => a1.map(i => a2.map(j => [i, j]));
console.log(matrix2d(range(5), range(6)));
I've been trying to find a reasonably concise way to set the dimensions of an empty multidimensional JavaScript array, but with no success so far.
First, I tried to initialize an empty 10x10x10 array using var theArray = new Array(10, 10 10), but instead, it only created a 1-dimensional array with 3 elements.
I've figured out how to initialize an empty 10x10x10 array using nested for-loops, but it's extremely tedious to write the array initializer this way. Initializing multidimensional arrays using nested for-loops can be quite tedious: is there a more concise way to set the dimensions of empty multidimensional arrays in JavaScript (with arbitrarily many dimensions)?
//Initializing an empty 10x10x10 array:
var theArray = new Array();
for(var a = 0; a < 10; a++){
theArray[a] = new Array();
for(var b = 0; b < 10; b++){
theArray[a][b] = new Array();
for(var c = 0; c < 10; c++){
theArray[a][b][c] = 10
}
}
}
console.log(JSON.stringify(theArray));
Adapted from this answer:
function createArray(length) {
var arr = new Array(length || 0),
i = length;
if (arguments.length > 1) {
var args = Array.prototype.slice.call(arguments, 1);
while(i--) arr[i] = createArray.apply(this, args);
}
return arr;
}
Simply call with an argument for the length of each dimension.
Usage examples:
var multiArray = createArray(10,10,10); Gives a 3-dimensional array of equal length.
var weirdArray = createArray(34,6,42,2); Gives a 4-dimensional array of unequal lengths.
function multiDimArrayInit(dimensions, leafValue) {
if (!dimensions.length) {
return leafValue;
}
var arr = [];
var subDimensions = dimensions.slice(1);
for (var i = 0; i < dimensions[0]; i++) {
arr.push(multiDimArrayInit(subDimensions, leafValue));
}
return arr;
}
console.log(multiDimArrayInit([2,8], "hi")); // counting the nested "hi"'s yields 16 of them
demo http://jsfiddle.net/WPrs3/
Here is my take on the problem: nArray utility function
function nArray() {
var arr = new Array();
var args = Array.prototype.slice.call(arguments, 1);
for(var i=0;i<arguments[0];i++) {
arr[i] = (arguments.length > 1 && nArray.apply(this, args)) || undefined;
}
return arr;
}
Usage example:
var arr = nArray(3, 3, 3);
Results in 3x3x3 array of undefined values.
Running code with some tests also available as a Fiddle here: http://jsfiddle.net/EqT3r/7/
The more dimension you have, the more you have interest in using one single flat array and a getter /setter function for your array.
Because for a [d1 X d2 X d3 X .. X dn] you'll be creating d2*d3*...*dn arrays instead of one, and when accessing, you'll make n indirection instead of 1.
The interface would look like :
var myNArray = new NArray(10,20,10);
var oneValue = myNArray.get(5,8,3);
myNArray.set(8,3,2, 'the value of (8,3,2)');
the implementation depends on your preference for a fixed-size
n-dimensionnal array or an array able to push/pop and the like.
A more succinct version of #chris code:
function multiDim (dims, leaf) {
dims = Array.isArray (dims) ? dims.slice () : [dims];
return Array.apply (null, Array (dims.shift ())).map (function (v, i) {
return dims.length
? multiDim (dims, typeof leaf == 'string' ? leaf.replace ('%i', i + ' %i') : leaf)
: typeof leaf == 'string' ? leaf.replace ('%i', i) : leaf;
});
}
console.log (JSON.stringify (multiDim ([2,2], "hi %i"), null, ' '));
Produces :
[
[
"hi 0 0",
"hi 0 1"
],
[
"hi 1 0",
"hi 1 1"
]
]
In this version you can pass the first argument as a number for single dimension array.
Including %i in the leaf value will provide index values in the leaf values.
Play with it at : http://jsfiddle.net/jstoolsmith/r3eMR/
Very simple function, generate an array with any number of dimensions. Specify length of each dimension and the content which for me is '' usually
function arrayGen(content,dims,dim1Len,dim2Len,dim3Len...) {
var args = arguments;
function loop(dim) {
var array = [];
for (var a = 0; a < args[dim + 1]; a++) {
if (dims > dim) {
array[a] = loop(dim + 1);
} else if (dims == dim) {
array[a] = content;
}
}
return array;
}
var thisArray = loop(1);
return thisArray;
};
I use this function very often, it saves a lot of time