Calculate Average value for multidimensional array - javascript

I have an example array. It contains a day and a number of failures of builds.
var array = [["2014-08-13",3],
["2014-08-13",3],
["2014-08-14",4],
["2014-08-12",2],
["2014-08-13",3],
["2014-08-12",2]];
I want to iterate through the array and get an array which holds for each day the average value of number of failures. I tried out some things but couldn't find a proper solution.
The target array should look like this:
var targetArray = [["2014-08-13",3],
["2014-08-14",4],
["2014-08-12",2]];
what I got so far is to make an array which holds the three dates:
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] == obj) {
return true;
}
}
return false;
}
var array = [
["2014-08-13", 3],
["2014-08-13", 3],
["2014-08-14", 4],
["2014-08-12", 2],
["2014-08-13", 3],
["2014-08-12", 2]];
var targetArray = [];
for (var i = 0; i < array.length; i++) {
var temporaryArr = [];
var current = array[i];
var currentDate = current[0];
var currentValue = current[1];
console.log("current: " + current);
if (!targetArray.contains(currentDate)) {
temporaryArr[0] = currentDate;
targetArray[targetArray.length] = temporaryArr;
}
}
console.log(targetArray);

First, your dates need to be strings or you'll start getting some really weird output:
var arr = [
['2014-08-13', 3],
['2014-08-13', 3],
['2014-08-14', 4],
['2014-08-12', 2],
['2014-08-13', 3],
['2014-08-12', 2]
];
Create a new object. We're going to use its keys to store our dates and values to store the failures and number of times that day has appeared.
var obj = {};
Loop over the array. If the key/date doesn't exist add it to the object and set the value to an array containing the number of failures and set the current count to 1. If the key/date does exist, add the number of fails to the fail total and increment the count.
for (var i = 0, l = arr.length; i < l; i++) {
var el = arr[i];
var date = el[0];
var fails = el[1];
if (!obj[date]) {
obj[date] = [fails, 1]
} else {
obj[date] = [obj[date][0] + fails, obj[date][1] + 1]
}
}
Finally loop over the object and push the date and average back to a new array.
var out = [];
for (var date in obj) {
out.push([date, obj[date][0] / obj[date][1]])
}
DEMO

Code below:
var array = [
["2014-08-13", 3],
["2014-08-14", 4],
["2014-08-13", 3],
["2014-08-12", 2],
["2014-08-13", 3],
["2014-08-12", 2]
];
function average(array) {
var ret = {}, retArr = [], tmp, time, value;
for(var i=0, len=array.length; i < len; i++) {
tmp = array[i];
time = tmp[0];
value = tmp[1];
if(time in ret) {
ret[time].push(value)
} else {
ret[time] = [value];
}
}
for(var p in ret) {
var total = 0;
ret[p].forEach(function(val) {
total += val;
});
retArr.push([p, total / ret[p].length]);
}
return retArr;
}
average(array);

var myArray = [["2014-08-13", 3],
["2014-08-13", 3],
["2014-08-14", 4],
["2014-08-12", 2],
["2014-08-13", 3],
["2014-08-12", 2]];
function getAverage(arr) {
var dates = [];
var values = [];
for(i=0; i<arr.length; i++){
var index = dates.indexOf(arr[i][0]);
if(index == -1){
dates.push(arr[i][0]);
values.push([arr[i][1]]);
}else{
values[index].push(arr[i][1]);
}
}
for(d=0; d<dates.length;d++){
var dateTotal = 0;
for(a=0;a<values[d].length;a++){ dateTotal += values[d][a] }
dates[d] = [dates[d], (dateTotal / values[d].length)]
}
return dates
};
getAverage(myArray);

Related

function to repeat same numbers y times

I am trying to write a function that returns the number x. y number of times. The function should be able to take in multiple 2d arrays. There will be only 2 elements per input array.
So for example: function([4,3][2,2][12,5])
//output should be exactly: 444, 22, 1212121212
I have solved most of the problem but I am stuck when x is a 2 digit number.
would appreciate some help in solving this. I must return the solution as a string with a comma (' ,') that separates the different arrays.
Here is my code as of now:
function repeatnumber(data){
var result = " ";
for (var i = 0; i < data.length; i++){
if (Array.isArray(data[i])){
var x = data[i][0]
var y = data[i][1]
for(var j = 1; j <= y; j++){
result = result + x;
}
}
}
var number = result
var answer = number.match(/(\d)\1*/g)
return console.log(answer);
}
repeatnumber([[10, 2][11,1]])// DOESN'T WORK!! output must be: 1010,11
repeatnumber([[1, 2], [2, 3]]) //works
repeatnumber([[1, 4], [3, 6], [9, 2]]) //works
You could check if you got a nested array and map new values and join later all arrays with comma.
function repeatnumber(array) {
return (Array.isArray(array[0]) ? array : [array])
.map(([value, length]) => Array.from({ length }, _ => value).join(''))
.join(', ');
}
console.log(repeatnumber([42, 7]));
console.log(repeatnumber([[10, 2], [11,1]]));
console.log(repeatnumber([[1, 2], [2, 3]]));
console.log(repeatnumber([[1, 4], [3, 6], [9, 2]]));
If you are using es6 this could be the simplest.
let repeatnumber = (inputArr) => {
return inputArr.map((inp) => `${inp[0]}`.repeat(inp[1]));
}
Here's one of the solution.
function repeatNumber(data) {
var results = '';
data.forEach(function(arr) {
for(var i = 0; i< arr[1]; i++) results += arr[0].toString();
results += ',';
})
return results.substring(0, results.length - 1);
}
console.log(repeatNumber([[10, 2], [11,1]]));
console.log(repeatNumber([[1, 2], [2, 3]]));
console.log(repeatNumber([[1, 4], [3, 6], [9, 2]]));
As you've noticed, regex isn't the best option. You're making the question a lot more difficult than it needs to be. You can just make an array of each of those strings and then join them together. Also, more descriptive variable names will go a long way for you.
let data = [[10,2], [11,1]]
function repeatNumber(data) {
let resultArray = []
for (let i=0; i < data.length; i++) {
let num = data[i][0]
let times = data[i][1]
let newString = ""
for (let j=0; j < times; j++) {
newString += num
}
resultArray.push(newString)
}
return resultArray.join(", ")
}
console.log(repeatNumber(data))
If you're ok with a code golf solution, this will accomplish the same task:
data.map(([num, times]) => Array(times).fill(num).join("")).join(", ")
try this :
function repeatnumber(data) {
var result = "";
for (var i = 0; i < data.length; i++)
{
if (Array.isArray(data[i]))
{
var x = data[i][0]
var y = data[i][1]
for(var j = 1; j <= y; j++)
{
{
result = result + x;
}
}
}
if(i != data.length - 1)
result += " ";
}
var number = result
var split = number.split(" ");
//var answer = number.match(/(\d)\1*/g)
return console.log(split);
}
repeatnumber([[10, 2][11,1]]) should be repeatnumber([[10, 2],[11,1]]);
ES6 Solution
const repeat = (arr) => {
arr.map( v => {
const str = new Array(v[1] + 1).join(v[0]);
console.log(str); // save this in array or wherever u want.
})
};
repeat([[1, 4], [3, 6], [9, 2]])
You are missing a comma between two arrays, make it
repeatnumber([[10, 2],[11,1]])
Also, your regex won't work properly when you are adding two digit number, change your logic as
function repeatnumber(data)
{
var answer = [];
for (var i = 0; i < data.length; i++)
{
if (Array.isArray(data[i]))
{
var x = data[i][0]
var y = data[i][1]
result = "";
for(var j = 1; j <= y; j++)
{
result = result + x;
}
answer.push(result)
}
}
return answer;
}
Demo
function repeatnumber(data) {
var answer = [];
for (var i = 0; i < data.length; i++) {
if (Array.isArray(data[i])) {
var x = data[i][0]
var y = data[i][1]
result = "";
for (var j = 1; j <= y; j++) {
result = result + x;
}
answer.push(result)
}
}
return answer;
}
console.log(repeatnumber([
[10, 2],
[11, 1]
])) ;
console.log(repeatnumber([
[1, 2],
[2, 3]
])) ;
console.log(repeatnumber([
[1, 4],
[3, 6],
[9, 2]
])) ;
Edit
Or a more concise method using fill and reduce
function repeatnumber(data)
{
return data.map( s => Array( s[1] ).fill( "" ).reduce( (a,c) => a + s[ 0 ], "" ) )
}
Or using fill and join
function repeatnumber(data)
{
return data.map( s => Array( s[1] + 1 ).fill( "" ).join( s[ 0 ] ) )
}
Small code that works,
// iterate > create array and join with char > join parent array with comma
function repeatnumber(data){
if(!data || data.length < 1) return [];
return data.map(arr => Array(arr[1] + 1).join(arr[0])).join(',');
}
A better approach, thanks to Ariz
function repeatnumber(data) {
if (!data || data.length < 1) return [];
return data.map((arr) => `${arr[0]}`.repeat(arr[1])).join(',');
}
No creation of an extra array, so huge repetitions can be done with ease.
Single pass by nested template literals and .reduce() working hand to hand.
var a = [[10, 2], [11,1]],
b = [[1, 2], [2, 3]],
c = [[1, 4], [3, 6], [9, 2]],
f = a => a.reduce((r,[v,c],i) => `${i ? `${r},`:``}${`${v}`.repeat(c)}`,``);
console.log(f(a));
console.log(f(b));
console.log(f(c));

find all subarrays in o(n) time 1D array using javascript

I want to collect all subarrays for further computation efficiently in javascript. I'm not sure this is possible, but it seems for a subarray sum kadane's formula is o(n) which is more efficient than other methods. But I'm not sure I how I can store the array at each step.
Similar to this quora question, for me the pseudo code was not enough. Thanks for the further breakdown.
another meta link
an example in action of this for [3, 3, 9, 9, 5]
[3], [9], [5], [9, 5], [9, 3], [9, 9], [3, 3],
[3, 9, 9], [3, 3, 9], [9, 9, 5], [3, 3, 9, 9],
[3, 9, 9, 5], [3, 3, 9, 9, 5]
I had done a work previously to calculate all combinations of amino acids total molecular weight. If you neglect the empty one you should have 2^n - 1 sub arrays. So there is no O(n) here. I've got two methods as binary and recursive.
function getSubArrays(arr){
var len = arr.length,
subs = Array(Math.pow(2,len)).fill();
return subs.map((_,i) => { var j = -1,
k = i,
res = [];
while (++j < len ) {
k & 1 && res.push(arr[j]);
k = k >> 1;
}
return res;
}).slice(1);
}
console.log(JSON.stringify(getSubArrays([1,2,3,4,5])));
function getSubArrays(arr){
if (arr.length === 1) return [arr];
else {
subarr = getSubArrays(arr.slice(1));
return subarr.concat(subarr.map(e => e.concat(arr[0])), [[arr[0]]]);
}
}
console.log(JSON.stringify(getSubArrays([1,2,3,4,5])));
I couldn't manage to get subarrays of an array with more than 23 items though.
Here are the performances. To be on the safe side i try with 22 items, first with recursive and then with binary route.
function getSubArrays(arr){
if (arr.length === 1) return [arr];
else {
subarr = getSubArrays(arr.slice(1));
return subarr.concat(subarr.map(e => e.concat(arr[0])), [[arr[0]]]);
}
}
var aminos = Array(22).fill().map((_,i) => i+1),
subarrs = [],
ps = 0,
pe = 0;
ps = performance.now();
subarrs = getSubArrays(aminos);
pe = performance.now();
console.log("recursive route took: " + (pe-ps) + "msec to produce " + subarrs.length + " sub arrays");
function getSubArrays(arr){
var len = arr.length,
subs = Array(Math.pow(2,len)).fill();
return subs.map((_,i) => { var j = -1,
k = i,
res = [];
while (++j < len ) {
k & 1 && res.push(arr[j]);
k = k >> 1;
}
return res;
}).slice(1);
}
var aminos = Array(22).fill().map((_,i) => i+1),
subarrs = [],
ps = 0,
pe = 0;
ps = performance.now();
subarrs = getSubArrays(aminos);
pe = performance.now();
console.log("binary route took: " + (pe-ps) + "msec to produce " + subarrs.length + " sub arrays");
This is fairly simple to do: https://jsfiddle.net/j1LuvxLq/
All you do is iterate possible lenghts and starting points and just print out the subsets. Complexity is O(n²) where n is the length of the original array. No way to improve it thought because that's the order of how many subsets there are.
var set = [3, 3, 9, 9, 5].join('')
var set_length = set.length
var subsets = []
for (var length_of_subset = 1; length_of_subset <= set_length; length_of_subset++) {
for (var start_of_subset = 0; start_of_subset <= set_length - length_of_subset; start_of_subset++) {
var current_subset = set.substring(start_of_subset, start_of_subset + length_of_subset)
if(subsets.indexOf(current_subset) == -1) {
subsets.push(current_subset.split(''))
}
}
}
// print the subsets out
for (s in subsets) {
$('body').append(subsets[s].join(', ') + '<br>')
}
Alternative, possibly nicer solution would be to use dynamic programming. Start with 3 and either remove last element or add next element. Check it out here: https://jsfiddle.net/p82fcs4m/
var set = [3, 3, 9, 9, 5].join('')
var subsets = []
take(set[0], set.substring(1))
function take(chosen, left) {
if(subsets.indexOf(chosen) != -1) {
return
}
subsets.push(chosen)
if (chosen.length > 1) {
take(chosen.substring(1), left)
}
if (left.length > 0) {
take(chosen.concat(left[0]), left.substring(1))
}
}
$('body').append(subsets.join('<br>'))
Try this:
function getSubArrays(arr) {
const subArrays = [];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr.length - i; j++) {
const subArray = arr.slice(i, j + i + 1);
subArrays.push(subArray);
}
}
}
Still O(n²) tho
I believe using Array.slice is the most clean way to do it, isn't it?
function getSubArrays(arr) {
const subArrays = [];
for (var i = 0; i < arr.length; i++) {
for (var j = i; j < arr.length; j++) {
subArrays.push(arr.slice(i, j + 1));
}
}
return subArrays;
}

Get small element index till array length

I have to sort an array and want to get index so that I can sort another array on the basis of this index..
There are two array a and b I saved division of that array in third array that is sortDiv now I want index of small element so that I can sort a and b according to index..
Code is like
var a = [6, 7, 8, 9];
var b = [1, 2, 3, 4];
var sortA = [],
sortB = [],
sortDiv = [];
var div = a[0] / b[0];
for (var i = 0; i < a.length; i++) {
sortDiv.push(a[i] / b[i]);
}
var temp = sortDiv;
for (var i = 1; i < sortDiv.length; i++) {
var val = Math.min.apply(Math, temp);
var key = sortDiv.indexOf(val);
sortA.push(a[key]);
sortB.push(b[key]);
if (key > -1)
temp.splice(key, 1);
}
console.log(sortA + " " + sortB);
I got [9,8] for a and [4,3] for b..while I want a=[9,8,7,6] b=[1,2,3,4]
But splice is not a good option..I need a function that remove only element not an index..any idea please?
UPDATED
As problem is solved but I want to know that
Is it possible to remove element but not an index in array?
Try not removing element just replacing it with maximum element +1 and it will work fine here is the updated code
var a = [6, 7, 8, 9];
var b = [1, 2, 3, 4];
var sortA = [],
sortB = [],
sortDiv = [];
var div = a[0] / b[0];
for (var i = 0; i < a.length; i++) {
sortDiv.push(a[i] / b[i]);
}
console.log(sortDiv);
var temp = sortDiv;
var max = Math.max.apply(Math, temp); // here we find the maximum
max += 1;
for (var i = 1; i <= sortDiv.length; i++) {
var val = Math.min.apply(Math, temp);
console.log(val);
var key = sortDiv.indexOf(val);
sortA.push(a[key]);
sortB.push(b[key]);
temp[key] = max; // here we update the minimum with maximum+1
}
console.log(sortA + " " + sortB);
If the question is about using splice to remove an item based on the value and not the index, get the index, then use splice:
var a = ['a', 'b', 'c'];
a.splice(a.indexOf('b'), 1);
console.log(a); // ["a", "c"]

Java Script - Adding null value to array, if the element is not present at particular index

Array length is 7
Original array
var arr = [2, 4, 6];
Needed array
arr = [null,null,2,null,4,null,6];
0 is not present in array so need to replace with null,
1 is not available replace with null and
2 is available so put 2 in new array so on..
You can use the splice() method on the array
var arr=[2,4,6];
var l = arr[arr.length-1];
for(var i=0; i<=l; i++){
if(arr[i] !== i){
arr.splice(i, 0, null);
}
}
Output : [null, null, 2, null, 4, null, 6]
This modifies the original array.
I will write a permanence case for all answers soon.
function createArrayFromArray(array, length) {
var new_array = new Array(length);
for (var i = 0; i < new_array.length; i++) {
new_array[i] = null;
}
for (var i = 0; i < array.length; i++) {
new_array[array[i]] = array[i];
}
return new_array;
}
console.log(createArrayFromArray(arr, 7)); //[null, null, 2, null, 4, null, 6]
You just need to find the max value in the array and then iterate from 0 to that max, checking each value to see if it was present in the source or not:
var arr = [2, 4, 6];
var max = Math.max.apply(Math, arr);
var result = [];
for (var i = 0; i <= max; i++) {
if (arr.indexOf(i) !== -1) {
result[i] = i;
} else {
result[i] = null;
}
}
Working demo: http://jsfiddle.net/jfriend00/c7p8mkqy/
As I asked in my comments, I'd like to know what problem you're actually trying to solve because it seems like both the original and the newly created data structures are inefficient structures that could probably use different form of data and work more efficiently. But, we can only help you make a wiser choice if you explain the actual problem, rather just your attempted solution.
Given you have the only input arr which you want to fill null inside. Try this:
var arr = [2, 4, 6];
var output = [];
while (arr.length>0){
var first = arr.splice(0,1);
while (output.length<first[0])
output.push(null);
output.push(first[0]);
}
// output should be [null,null,2,null,4,null,6];
Try:
var arr = [2, 4, 6];
var new_arr = [];
var i = 0;
while(i < 7){
var pos = arr.indexOf(i++);
new_arr.push(pos !== -1 ? arr[pos] : null)
}
document.write(JSON.stringify(new_arr, null, 4))
var arr = [2, 4, 6];
var result = new Array(7);
arr.forEach(function(a) { result[a] = a;});
Interesting quiz:
var arr = [2, 4, 6]
var n = 0
while(arr.length > n) {
if(arr[n] !== n) {
arr = arr.slice(0,n).concat(null, arr.slice(n))
}
n++
}
console.log(arr) // [null, null, 2, null, 4, null, 6]
This approach applies to array consists of random number of sorted integers.
var arr = [2, 4, 6];
var narr = (new Array(arr.sort()[arr.length-1]))
arr.map(function(v){
narr[v] = v;
});
for (var i = 0; i<narr.length; i++) narr[i]||(narr[i]=null);
console.log(narr);
Try splice():
var arr = [2, 4, 6];
var i = 0,
l = arr[arr.length - 1];
while (i < l) {
if(i !== arr[i])
arr.splice(i, 0, null);
i++;
}
console.log(arr); //[ null, null, 2, null, 4, null, 6 ]

Average jagged array by index

I have an array of arrays that looks like: var data = [[2, 2,3], [3, 9], [5, 6,7,8]];
(fiddle here)
I need to be able to create a new array based on each inner array's index. So from the above output I'm looking for
1 - [2,3,5]
2 - [2,9,6]
3 - [3,7]
4 - [8]
helper average method:
Array.prototype.average = function () {
var sum = this.sum();
return sum / this.length;
};
I've got something like :
var data = [[2, 2,3], [3, 9], [5, 6,7,8]];
//Sconsole.log(data);
Array.prototype.averageAll = function () {
var avgArrays = [[]];
var self = this;
for (var i = 0; i < self.length; i++) {
avgArrays[0].push(self[i][0]);
}
return avgArrays[0].average();
};
//3.333 to the console
console.log(data.averageAll());
I've hardcoded in the season here because if I try to use avgArrays[i][i] I get an error push is not defined. For my simple example, the function calculates the average of the 0th position of each array in the array. If I have arrays of varying sizes like this, how can I make this go slickly in one fell swoop?
reduce can be handy here-
var data= [[2, 2, 3], [3, 9], [5, 6, 7, 8]];
data.Average= function(itm){
return data.Sum(itm)/(itm.length);
}
data.Sum= function(itm){
return itm.reduce(function(a, b){
return a+b
});
}
data.map(data.Average);
/* returned value: (Array)
2.3333333333333335,6,6.5
*/
A comment reminded me to add a 'shim' for IE8 and lower- the other browsers get map and reduce-
(function(){
var ap= Array.prototype; //IE8 & lower
if(!ap.map){
ap.map= function(fun, scope){
var T= this, L= T.length, A= Array(L), i= 0;
if(typeof fun== 'function'){
while(i<L){
if(i in T){
A[i]= fun.call(scope, T[i], i, T);
}
++i;
}
return A;
}
};
}
if(!ap.reduce){
ap.reduce= function(fun, temp, scope){
var T= this, i= 0, len= T.length, temp;
if(typeof fun=== 'function'){
if(temp== undefined) temp= T[i++];
while(i<len){
if(i in T) temp= fun.call(scope, temp, T[i], i, T);
i++;
}
}
return temp;
}
}
})();
Array.prototype.sum = function () {
var total = 0;
for (var i = 0; i < this.length; i++) {
total += this[i];
}
return total;
};
Array.prototype.average = function () {
var sum = this.sum();
return sum / this.length;
};
var data = [[2, 2,3], [3, 9], [5, 6,7,8]];
//Sconsole.log(data);
Array.prototype.averageAll = function () {
var avgArrays = [];
var self = this;
//in an array of arrays, val is an array
var maxLen = 0;
for(var i = 0; i < self.length; i++) {
if(self[i].length > maxLen)
{
maxLen = self[i].length;
}
}
console.log('maxlen is ' + maxLen);
for(var j = 0; j < maxLen; j++) {
avgArrays.push([]);
for(var k = 0; k < self.length; k++) {
if(self[k][j]){
avgArrays[j].push(self[k][j]);
}
}
}
console.log(avgArrays);
var result = []
for (var x = 0; x < avgArrays.length; x++) {
result.push(avgArrays[x].average());
}
return result;
};
console.log(data.averageAll());
I think the following code should construct your array for you:
var data = [[2, 2,3], [3, 9], [5, 6,7,8]];
var max = 0;
for(var i = 0; i < data.length; i++) {
max = data[i].length > max ? data[i].length : max
}
var result = [];
for(var i = 0; i < max; i++) {
result[i] = [];
for(var j = 0; j < data.length; j++) {
if(i < data[j].length) {
result[i].push(data[j][i]);
}
}
}
After that, it is trivial to calculate the average:
var averages = [];
for(var i = 0; i < result.length; i++) {
var array = result[i];
var sum = 0;
for(var j = 0; j < array.length; j++) {
sum += array[j];
}
averages.push(sum / array.length);
}
Fiddle here.
So if I understood correctly, you want a new array made up of averages of your sub arrays?
Here is a simple way to do it, by leveraging built-in array functions
var data = [[2, 2,3], [3, 9], [5, 6,7,8]];
var averageAll = function(arr) {
return arr.map(function(a) {
return a.reduce(function(b,c) { return b+c; })/a.length;
});
};
averageAll(data);
// -> [2.3333333333333335, 6, 6.5]
Also, as a rule of thumb, don't mess with the standard types' prototypes, in my experience it only leads to trouble.
var data = [
[2, 2, 3],
[3, 9],
[5, 6, 7, 8]
];
Array.prototype.averageAll = function() {
var result = [],
maxIdx = Math.max.apply(Math, this.map(function(arr) { return arr.length }));
for (var i = 0; i < maxIdx; i++) {
var sum = this.reduce(function(old, cur) {
return old + (cur[i] || 0);
}, 0);
result.push(sum / this.length);
}
return result;
};
console.log(data.averageAll());
//[3.3333333333333335, 5.666666666666667, 3.3333333333333335, 2.6666666666666665]
fiddle

Categories