How would I go about calculating the average of all the values in a multidimensional array? I've written a function to calculate the average from a 1-dimensional array, but I'm not sure what the best method is when there are more than 1-dimensions.
For example, let's say we have the following:
var A = Array(3);
for (i=0; i<A.length; i++) {
A[i] = new Array(2);
for (j=0; j<A[i].length; j++) {
A[i][j] = i+j;
}
}
Therefore, A is a 2-dimensional array, or 3x2 matrix:
A = 0 1
1 2
2 3
So I'd like to find the average of all the values, which in this case would equal 1.5. I imagine I need to create a new 1-dimensional array of all the values, which I could then feed into my averaging function. However, I'm not sure of the easiest way to do this when the array is highly-dimensional (e.g. 5x3x6x9).
Thanks!
EDIT
Thanks everyone! I've used your advice and flattened the array using code I found in one of the attached links which uses the reduce function. My averaging function is now like this:
function average(x) {
// Flatten multi-dimensional array
while (x[0] instanceof Array) {
x = x.reduce( function(a, b) { return a.concat(b); } );
}
// Calculate average
return x.reduce( function(a, b) { return a + b; } )/x.length;
}
You can use this code to flatten the multi-dimensional array:
function flatten(array){
var flat = [];
for (var i = 0, l = array.length; i < l; i++){
var type = Object.prototype.toString.call(array[i]).split(' ').pop().split(']').shift().toLowerCase();
if (type) { flat = flat.concat(/^(array|collection|arguments|object)$/.test(type) ? flatten(array[i]) : array[i]); }
}
return flat;
}
and then just sum and divide:
var total = 0;
for (var i = 0, l = flattenedArray.length; i<l; i++) {
total += flattenedArray[i];
}
var average = total/flattenedArray.length;
I don't see any particular reason you need to create a new array. Just loop through the ones you have:
var i, j, sub, total, count, avg;
total = count = 0;
for (i = 0; i < A.length; ++i) {
sub = A[i];
count += sub.length;
for (j = 0; j < sub.length; ++j) {
total += sub[j];
}
}
avg = count === 0 ? NaN : total / count;
Note that the above assumes the arrays are not sparse (they aren't in your example).
// The simplest method is to flatten the array
Array.prototype.flatten= function(){
var A= [];
this.forEach(function(itm){
if(!itm || !itm.flatten)A.push(itm);
else{
A= A.concat(itm.flatten());
}
});
return A;
}
// shim for older browsers (without array forEach)
Array.prototype.forEach= [].forEach || function(fun, scope){
var T= this, L= T.length, i= 0;
if(typeof fun== 'function'){
while(i< L){
if(i in T){
fun.call(scope, T[i], i, T);
}
++i;
}
}
return T;
}
var a=[[1,2,3,[1,2,3]],[4,5,6,[7,8,[1,2,3,[1,2]]]],11,[1,[2,[2,4,[5]]]]];
a.flatten().join('\n')
/* returned value: (String)
1
2
3
1
2
3
4
5
6
7
8
1
2
3
1
2
11
1
2
2
4
5
*/
You can flatten your multidimensional-array with this function:
function flatten(arr) {
var acc = [];
var f = function(arr) {
for (var i = 0; i < arr.length; ++i) {
if (arr[i] instanceof Array) {
f(arr[i]);
}
else {
acc.push(arr[i]);
}
}
};
f(arr);
return acc;
}
And then you can calculate the average with your function.
Related
I want to find all possible arrays -of non-negative numbers- that sum up to -at most- N in JavaScript:
function findArrays(maxSize, maxSum){}
Example input: findArrays(3, 10)
Some acceptable outputs: (not writing all as it would be too long)
[[0], [0,0,0], [10,0,0], [1,9], [1,2,3] /*, ... */]
What I tried so far:
I know it looks like homework but it's not :) I can think of a solution that simply generates all (size*maxSum) possible arrays of acceptable sizes and then iterate through them to check if sum is greater than maxSum. However, I think this solution is very bad in terms of performance as maxSum gets bigger. I'm looking for a more efficient implementation but I just don't know where to start.
My "bad" solution
function getNextArray(r,maxVal){
for(var i=r.length-1;i>=0;i--){
if(r[i]<maxVal){
r[i]++;
if(i<r.length-1){
r[i+1]=0;
}
break;
}
}
return r;
}
function getAllArraysOfSize(size, maxVal){
var arrays=[],r=[],i;
for(i=0;i<size;i++){
r[i]=0;
}
while(r.reduce((a, b) => a + b, 0) < (maxVal*size)){
r = getNextArray(r.slice(),maxVal);
arrays.push(r);
}
return arrays;
};
function findArrays(maxSize, maxSum){
var allArrays=[],arraysOfFixedSize=[],acceptableArrays=[],i,j;
for(i=1; i<=maxSize; i++){
arraysOfFixedSize=getAllArraysOfSize(i,maxSum);
for(j=0; j<arraysOfFixedSize.length; j++){
allArrays.push(arraysOfFixedSize[j]);
}
}
for(i=0; i<allArrays.length; i++){
if(allArrays[i].reduce((a, b) => a + b, 0) <= maxSum){
acceptableArrays.push(allArrays[i]);
}
}
return acceptableArrays;
};
You can use recursion and a generator. The number of outputs grows quickly for higher valued arguments, so I keep them low here:
function * findArrays(maxSize, maxSum) {
let arr = [];
function * recur(maxSum) {
let k = arr.length;
yield [...arr]; // or: if (k) yield [...arr]
if (k === maxSize) return;
for (let i = 0; i <= maxSum; i++) {
arr[k] = i;
yield * recur(maxSum - i);
}
arr.length = k;
}
yield * recur(maxSum);
}
// demo
for (let arr of findArrays(2, 4))
console.log(JSON.stringify(arr));
NB: this also produces the empty array, which makes sense. If you want to avoid this, then just check that you don't yield an empty array.
If you prefer working with plain functions instead of generators, then translate the innermost yield expression to a push unto a result array, as follows:
function findArrays(maxSize, maxSum) {
let arr = [];
let result = []; // <--- will collect all the subarrays
function recur(maxSum) {
let k = arr.length;
result.push([...arr]);
if (k === maxSize) return;
for (let i = 0; i <= maxSum; i++) {
arr[k] = i;
recur(maxSum - i);
}
arr.length = k;
}
recur(maxSum);
return result;
}
// demo
for (let arr of findArrays(2, 4))
console.log(JSON.stringify(arr));
i hope this is helpful
const data = [[0],[0,0,0],[10,0,0],[1,9],[1,2,3]];
function findArrays(maxSize, maxSum){
return data.reduce(
(acc, value) => {
if (value.length <= maxSize) {
const tempValue = value;
const sum = tempValue.reduce((acc, val) => val >= 0 ? acc + val : 0, 0);
if (sum <= maxSum && sum > 0) acc.push(value);
}
return acc
}, []
)
}
console.log(findArrays(3, 10));
Please help me to solve this leetcode problem using javascript as I am a beginner and dont know why this code is not working
Ques: Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
var findDisappearedNumbers = function (nums) {
var numLength = nums.length;
nums.sort(function (a, b) { return a - b });
for (var i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] === nums[i]) {
nums.splice(i, 1);
}
}
for (var k = 0; k < nums.length; k++) {
for (var j = 1; j <= numLength; j++) {
if (nums[k] !== j) {
return j;
}
}
}
};
if there is any error in my code please let me know;
i have done the following thing
first i have sorted the array in ascending order
then i have cut all the duplicate elements
then i have created loop that will check if nums[k] !== j ;
and it will return j which is the missing number;
for example this is the testcase [4,3,2,7,8,2,3,1]
first my code will sort this in ascending order [1,2,2,3,3,4,7,8]
then it will remove all duplicate elements and it will return [1,2,3,4,,7,8]
and then it will check nums[k] is not equal to j and it will print j
I think it'd be easier to create a Set of numbers from 1 to n, then just iterate through the array and delete every found item from the set:
var findDisappearedNumbers = function(nums) {
const set = new Set();
for (let i = 0; i < nums.length; i++) {
set.add(i + 1);
}
for (const num of nums) {
set.delete(num);
}
return [...set];
};
console.log(findDisappearedNumbers([4,3,2,7,8,2,3,1]));
To fix your existing code, I'm not sure what the logic you're trying to implement in the lower section, but you can iterate from 1 to numLength (in the outer loop, not the inner loop) and check to see if the given number is anywhere in the array. Also, since you're mutating the array with splice while iterating over it in the upper loop, make sure to subtract one from i at the same time so you don't skip an element.
var findDisappearedNumbers = function(nums) {
var numLength = nums.length;
nums.sort(function(a, b) {
return a - b
});
for (var i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] === nums[i]) {
nums.splice(i, 1);
i--;
}
}
const notFound = [];
outer:
for (var j = 1; j < numLength; j++) {
for (var k = 0; k < nums.length; k++) {
if (nums[k] === j) {
continue outer;
}
}
notFound.push(j);
}
return notFound;
};
console.log(findDisappearedNumbers([4, 3, 2, 7, 8, 2, 3, 1]));
#CertainPerformance certainly cracked it again using the modern Set class. Here is a slighly more conservative approach using an old fashioned object:
console.log(missingIn([4,3,2,7,8,2,3,1]));
function missingIn(arr){
const o={};
arr.forEach((n,i)=>o[i+1]=1 );
arr.forEach((n) =>delete o[n] );
return Object.keys(o).map(v=>+v);
}
My solution for the problem to find the missing element
var findDisappearedNumbers = function(nums) {
const map={};
const result=[];
for(let a=0;a<nums.length;a++){
map[nums[a]]=a;
}
for(let b=0;b<nums.length;b++){
if(map[b+1]===undefined){
result.push(b+1)
}
}
return result;
};
Example 1:
Input: nums = [4,3,2,7,8,2,3,1]
Output: [5,6]
Example 2:
Input: nums = [1,1]
Output: [2]
This question already has answers here:
How to find the sum of an array of numbers
(59 answers)
Closed 6 years ago.
How can I turn this into a function that takes an array of any length and gives you the total?
var points = new Array(100);
for (var i = 0; i < 100; i++) {
points[i] = i + 1;
}
for(var i = 0; i < points.length; i++) {
console.log(points[i]);
}
You could do it in two loops, but you might as well just do one loop that does both tasks.
var array = [],
sum = 0;
for (var i = 1; i <= 10000; i++) {
array[i-1] = i;
sum += i;
}
If you want to generalize the task of finding the sum of an array, you can use a function like so:
function arraySum(array) {
var sum = 0;
for (var i = 0; i < array.length; i++)
sum += array[i];
return sum;
}
For those who can understand it though, using reduce is a best answer:
function arraySum(array) {
return array.reduce(function(a,b){return a+b}, 0);
}
You can do get the sum using the for loop itself simply by using a variable
var points = new Array(100),
sum = 0;
for (var i = 0; i < 100; i++) {
points[i] = i + 1;
}
for (var i = 0; i < points.length; i++) {
sum += points[i];
}
console.log(sum);
You can reduce these two operations using fill() and forEach() to generate the array and reduce() to get the sum
var points = new Array(10000); // create an array of size 10000
points.fill(1); // fill it with 1 which helps ti=o iterate using foreach
points.forEach(function(v, i) { // iterate the array, you can also use simple for loop here
points[i] = v + i; // update the value
});
var sum = points.reduce(function(a, b) { // find sum
return a + b;
});
console.log(sum);
Using for loop and reduce()
var points = []; // initialize an array
for (var i = 1; i <= 10000; i++) {
points.push(i);
}
var sum = points.reduce(function(a, b) { // find sum
return a + b;
});
console.log(sum);
Also you can do the addition and array creation in single for loop
var points = [], // initialize an array
sum = 0;
for (var i = 1; i <= 10000; i++) {
points.push(i); // pushing value to array
sum += i; // summation
}
console.log(sum, points);
var result = 0;
for(var i = 0; i < points.length; i++) {
result += points[i];
}
Function that takes an array of any length and returns the sum:
function sumArray(arrayToSum){
var result = 0;
for(var i = 0; i < arrayToSum.length; i++) {
result += points[i];
}
return result;
}
function arraysum(arraylength) {
var arraysum = 0;
var array1 = new Array();
for(i=1; i<=arraylength; i++) {
array1.push(i);
}
for(i = 0; i< array1.length; i++) {
arraysum += array1[i];
}
return arraysum;
}
Now when you call the function
arraysum(x)
pass the function some variable or integer for example 1, 15, or 10000.
A very elegant and compact solution is to use reduce. It accumulates the array values to reduce it to a single value by applying each value and a start value to a given function, whose return value is used as the start value for the next iteration:
function sum (a, b) {
return a + b;
}
console.log(points.reduce(sum, 0));
If you need to support older browser (e.g. IE 8) you can use a Polyfill.
If you need to create the list of numbers as well, you can create it with
var points = Array.apply(0, Array(10000))
.map(function (current, index) {
return index + 1;
});
It creates an array of 10000 elements and assigns each element it's index + 1.
Guys I need your opinion; I've encountered this earlier during my interview, I just want to confirm I understood the question right and I got the answer correctly. Thank you. Please check the question and my answer below:
Take an input single dimensional array [1,2,3,4] and output the product of the integers excluding the current index [24,12,8,6];
//My answer
function calculate(values:Array):Array {
var resultArray:Array = new Array();
for(var i:int = 0; i < values.length; i++) {
var getVal1:Number = 1;
for(var k:int = 0; k <= values.length; k++) {
if(i != k) {
var getVal2:Number = values[k];
getVal1 *= getVal2;
}
}
resultArray.push(getVal1);
}
return resultArray;
}
Nested loops seems like a very messy way to go.
Assuming relatively up-to-date browser (IE 8 and below are out) or suitable shim:
var resultArray = sourceArray.map(function(val,ind,arr) {
arr = arr.slice(0); // create copy of array to work on here
arr.splice(ind,1); // remove current item from array
return arr.reduce(function(prev,curr) {return prev*curr;},1);
});
Array.prototype.map
Array.prototype.reduce
EDIT Here's another way that should be more efficient:
var product = sourceArray.reduce(function(prev,curr) {return prev*curr;},1);
var resultArray = sourceArray.map(function(val) {return product/val;});
Your solution gives the correct answer, but there is a much more efficient method to calculate the new array:
function calculate(values:Array):Array {
var resultArray:Array = new Array();
var product:int = 1;
for(var i:int = 0; i < values.length; i++) {
product *= values[i];
}
for(var i:int = 0; i < values.length; i++) {
resultArray.push(product / values[i]);
}
return resultArray;
}
This solution has O(n) execution time, while your code has O(n²) execution time.
That should work. You can do it easier and more efficiently by multiplying all items first:
function calculate(values) {
var prod = 1;
for (var i = 0; i < values.length; i++) prod *= values[i];
var result = [];
for (i = 0; i < values.length; i++) result.push(prod / values[i]);
return result;
}
I believe that my code below is very easy to read. And has no nested loops, but two consecutives. My answer would be:
function calculate(array){
var total = array.reduce(function(a, b){
return a * b;
});
return array.map(function(element){
return total / element;
});
}
Though I like #Kolink's short-and-efficient solution best, here's another way to solve the task - not using division but still being in O(n):
function calculate(values) {
var acc = 1,
l = values.length,
result = new Array(l);
for (var i=0; i<l; i++) {
result[i] = acc;
acc *= values[i];
}
acc = 1;
while(i--) {
result[i] *= acc;
acc *= values[i]
}
return result;
}
Or, the same thing but a little obfuscated*:
function calculate(values) {
var acc = 1,
i = 0,
l = values.length,
result = new Array(l);
if (l)
result[i] = 1;
while( ++i < l)
result[i] = acc *= values[i-1];
i -= acc = 1;
while (i--)
result[i] *= acc *= values[i+1];
return result;
}
*: I like shorthand operators!
I tried to write some javascript that takes the entries of an array and shuffles the order. It's not compiling like it should though. Seems to only run through the for loop once. What am I missing?
//random number between 1 and num
function randInt(num){
return Math.floor(num*Math.random()+1);
}
//shuffles deck (array) of any size
function shuffle(array){
var newArray = new Array();
var n = array.length;
for(i=0; i<n; i++){
var entry = randInt(array.length) - 1;
newArray[i] = array[entry]; //assigns random entry in initial array to new array
array = array.splice(entry, 1); //removes the entry that was stored into newArray
}
array = newArray;
}
array.splice modifies array and returns the removed item(s). You want to discard the element, so just do this instead of overwriting array:
array.splice(entry, 1);
+ 1 in randInt and doing - 1 afterwards seems superflouous.
Use var i = 0 (though look at my last point).
Use [] instead of new Array() since the latter is not generally used.
Return the new array instead of overwriting array:
return newArray;
You modify array so you cannot loop up to n anymore as the length becomes 1 less each time. You may want while(array.length > 0) { ... } instead of the for loop.
The fundamental problem you're having here is that your code is written as if JavaScript were a call-by-reference language. It's not; it's call-by-value. Thus, the last line of the function is syntactically correct but functionally useless.
Here's the Fisher-Yates shuffle:
function fyShuffle(a) {
if (a.length < 2) return;
for (var i = a.length; --i >= 1; ) {
var j = ~~(Math.random() * (i + 1)), tmp;
tmp = a[j];
a[j] = a[i];
a[i] = tmp;
}
}
Dont need to re-invent the wheel (in this case the shuffle).
function shuffle(o){
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
http://snippets.dzone.com/posts/show/849
Why not just use array.sort with a custom function?
function shuffle(array) {
array.sort(function(a, b) {
return (Math.random() < 0.5) ? 1 : -1;
});
}
Array.prototype.shuffle= function(){
var i, L= this.length;
while(--L){
i= Math.floor(Math.random()*L);
this[L]= this.splice(i, 1, this[L])
}
return this;
}
Hard to say if using splice is quicker than direct assignment-
Array.prototype.shuffle= function(){
var i, temp, L= this.length;
while(--L){
i= Math.floor(Math.random()*L);
temp= this[i];
this[i]= this[L];
this[L]= temp;
}
return this;
}