Let's say I have an Array who's item length is too big for some maxLength
var maxLength = 3;
var arr = [1,2,3,4,5];
var tooBig = arr.length > maxLength;
Is there an optimized algorithm for reducing this array in length by combining item values?
if(tooBig){
var newArr = refactor(arr, maxLength);
console.log(newArr); //[5,5,5]
}
Evenly re-distributing as much as possible is important:
//Could be reduced more evenly like above
console.log(newArr); //[1,6,8]
The basic idea is to get the sum of the current array. Extract the reminder, and get an average without the reminder. Then create a new array, and populate it with the average + 1 as long as the reminder is greater than 0.
function refactor(arr, maxLength) {
var sum = arr.reduce(function(s, n) {
return s + n;
});
var remainder = sum % maxLength;
var average = (sum - remainder) / maxLength;
var arr = [];
for(var i = 0; i < maxLength; i++) {
arr.push(average + (i < remainder));
}
return arr;
}
var maxLength = 3;
var arr = [1,2,3,4,6];
var tooBig = arr.length > maxLength;
if(tooBig){
var newArr = refactor(arr, maxLength);
console.log(newArr); //[6,5,5]
}
If you don't need the array items to be integers, you can get the average directly, and set it as the value of each array item:
function refactor(arr, maxLength) {
var average = arr.reduce(function(s, n) {
return s + n;
}) / maxLength;
var arr = [];
for(var i = 0; i < maxLength; i++) {
arr.push(average);
}
return arr;
}
var maxLength = 3;
var arr = [1.7,2.4,3,4,6.934];
var tooBig = arr.length > maxLength;
if(tooBig){
var newArr = refactor(arr, maxLength);
console.log(newArr);
}
I want to generate an addition equation for a random number which is look likes
5+10+2 from a set of numbers i.e [1,2,5,10,50].
var randomNumber = Math.floor(Math.random() * (10 - 1 + 1)) + 1;
var setOfNums = [1,2,5,10,50];
var additionEquation; //ex: for randomNumber = 28; additionEquation = 10+10+5+2+1;
And the maximum number of elements in equation is 5.Is it possible in java script?Thanks in advance.
You may have multiple solutions. A dynamical programming approach could efficiently solve this;
function getCombos(a,t){
var h = {},
len = a.length,
n = 0;
for (var i = 0; i < len; i++){
n = a[i];
h[n] ? h[n].push([n]) : h[n] = [[n]];
for(var j = a[0]; j <= t-n; j++){
h[j] && (h[j+n] = h[j+n] ? h[j+n].concat(h[j].map(s => s.concat(n)))
: h[j].map(s => s.concat(n)));
}
}
return h[t] || [];
}
var arr = [1,2,5,10,50],
target = 28,
result = [];
console.time("combos");
result = getCombos(arr,target);
console.timeEnd("combos");
console.log(`${result.length} solutions found`);
console.log(JSON.stringify(result));
Then you may choose the shortest one among the results set. However calculating according to a maxlen will of couse save us from calculating excess results just to be filtered out later. So the following code only works up until the maxlen is achieved.
function getCombos(a,t,l){
var h = {},
len = a.length,
n = 0;
for (var i = 0; i < len; i++){
n = a[i];
h[n] ? h[n].push([n]) : h[n] = [[n]];
for(var j = a[0]; j <= t-n; j++){
h[j] && (h[j+n] = h[j+n] ? h[j+n].concat(h[j].reduce((r,s) => s.length < l ? (r.push(s.concat(n)),r) : r, []))
: h[j].reduce((r,s) => s.length < l ? (r.push(s.concat(n)),r) : r, []));
}
}
return h[t] || [];
}
var arr = [1,2,5,10,50],
target = 28,
maxlen = 5,
result = [];
console.time("combos");
result = getCombos(arr,target,maxlen);
console.timeEnd("combos");
console.log(result.length)
console.log(JSON.stringify(result));
I believe performance wise this can not be beaten easily. It takes only .190ms to get to the result [[1,2,5,10,10]].
This problem can be solved with a recursive combinations of all possible sums until we reach the target.
One solution contains maximum 5 as a length where 5 is the length of the setOfNums array.
var randomNumber = Math.floor(Math.random() * 30) + 1;
console.log(randomNumber);
var setOfNums = [1,2,5,10,50];
setOfNums=setOfNums.sort(function(a,b){
return b-a;
});
subset_sum(setOfNums,randomNumber);
function subset_sum(numbers, target, partial){
partial = partial || [];
s = partial.reduce(function(contor,elem){
return contor+elem;
},0);
if(s == target){
partial=partial.sort(function(a,b){
return a-b;
});
console.log("sum"+JSON.stringify(partial)+"="+ target);
}
if(s >= target)
return;
if(partial.length>numbers.length)
return;
numbers.forEach(function(number,index){
n = numbers[index];
subset_sum(numbers, target, partial.concat(n));
});
}
Starting with this initial 2D array:
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
I need to create this 3D array programmatically:
var fullArray = [
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]],
[[6,7],[3,4],[1,2],[5,6],[2,3],[6,7]],
[[0,1],[4,5],[2,3],[6,7],[3,4],[0,1]],
[[1,2],[5,6],[3,4],[0,1],[4,5],[1,2]],
[[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]],
[[3,4],[0,1],[5,6],[2,3],[6,7],[3,4]],
[[4,5],[1,2],[6,7],[3,4],[0,1],[4,5]],
[[5,6],[2,3],[0,1],[4,5],[1,2],[5,6]]
];
See the pattern?
On each pair, the [0] position should increment to 6 (from any starting number <= 6) and then reset to 0 and then continue incrementing. Similarly, the [1] position should increment to 7 (from any starting number <= 7) and then reset to 1 and then continue incrementing.
In this example, there are 10 2D arrays contained in the fullArray. However, I need this number to be a variable. Something like this:
var numberOf2DArraysInFullArray = 12;
Furthermore, the initial array should be flexible so that initialArray values can be rearranged like this (but with the same iteration follow-through rules stated above):
var initialArray = [[6,7],[2,3],[5,6],[4,5],[1,2],[6,7]];
Any thoughts on how to programmatically create this structure?
Stumped on how to gracefully pull this off.
Feedback greatly appreciated!
Here's a solution, I've separated the methods, and I made it so if instead of pairs it's an N size array and you want the [2] to increase up to 8 and reset to 2, if that's not needed you can simplify the of the loop for(var j = 0; j < innerArray.length; j++)
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var create3DArray = function(array, size){
var newArray = [initialArray];
for(var i = 0; i < size; i++)
{
newArray.push(getNextArrayRow(newArray[i]));
}
return newArray;
}
var getNextArrayRow = function(array){
var nextRow = [];
for(var i = 0; i < array.length; i++)
{
var innerArray = array[i];
var nextElement = [];
for(var j = 0; j < innerArray.length; j++)
{
var value = (innerArray[j] + 1) % (7 + j);
value = value === 0 ? j : value;
nextElement.push(value);
}
nextRow.push(nextElement);
}
return nextRow;
}
console.log(create3DArray(initialArray,3));
Note, the results from running the snippet are a bit difficult to read...
var initialArray = [[2,3],[6,7],[4,5],[1,2],[5,6],[2,3]];
var numOfArrays = 10;
// get a range array [0, 1, 2, ...]
var range = [];
for (var i = 0; i < numOfArrays; i++) {
range.push(i);
}
var result = range.reduce(function(prev, index) {
if (index == 0) {
return prev;
}
prev.push(transformArray(prev[index - 1]));
return prev;
}, [initialArray])
console.log(result);
function transformArray(arr) {
return arr.map(transformSubArray)
}
function transformSubArray(arr) {
return arr.map(function(val) {
return val == 7 ? 0 : val + 1;
})
}
Here's a pretty simple functional-ish implementation
I have an array:
var myarray = [1,2,3,4,7,9,12,13,14]
I need to group values like so:
var array_1 = 1,2,3,4
var array_2 = 7
var array_3 = 8
var array_4 = 12,13,14
I need to find a sequences with an arithmetic progression and seperate from other values.
Any ideas?
Check out this solution
function explode(myarray)
{
var multi = [];
var i = j = 0;
for ( key in myarray )
{
if((myarray[key-1]) != (myarray[key]-1))
{
i++;
j=0;
}
if(j==0)
multi[i] = [];
multi[i][j] = myarray[key];
j++;
}
return multi;
}
It returns a multidimentionnal array that you can use in your example like this
var myarray = [1,2,3,4,7,9,12,13,14];
var multi_array = explode(myarray);
var array_1 = multi_array[0];
var array_2 = multi_array[1];
var array_3 = multi_array[2];
var array_4 = multi_array[3];
New update :
You can also remove the j index and use .push to add new elements to your array
function explode(myarray)
{
var multi = [];
var i = 0;
for ( key in myarray )
{
if((myarray[key-1]) != (myarray[key]-1))
i++;
if(!multi[i])
multi[i] = [];
multi[i].push(myarray[key]);
}
return multi;
}
The following seems to work, but displays a slightly different output than the one you expect.
In your example, I think 7 and 9 should be grouped (any sequence of two items is an arithmetic
progression after all). Or if they are not grouped, then 12 should not be grouped with 13 and
14 either, since 12-9 != 13-12
function split(arr) {
if (arr.length < 2) {
return;
}
var delta = undefined;
var start = 0;
for (var idx = 1; idx < arr.length; idx++) {
if (delta === undefined) {
delta = arr[idx] - arr[idx - 1];
}
if (arr[idx] - arr[idx - 1] != delta) {
alert("subarray " + arr.slice(start, idx));
start = idx;
delta = undefined;
}
}
alert("subarray from" + arr.slice(start, arr.length));
}
split([1,2,3,4,7,9,12,13,14]);
arrays = Array();
var c = 0;
array[c][] = myarray[0]);
for (var i = 1; i<myarray.length; i++) {
if (myarray[i-1] +1 != myarray[i])
c++;
array[c][] = push(myarray[i]);
}
not sure the array syntax (might mix up languages here) is correct or whether I understand your problem fully.
I've got an array that is constantly updating with analogue readings from an Arduino pin.
I'd like to create a function that takes the latest 100 values in the array, and returns an average of them (the array has a max length of 100,000 at which it starts 'shifting' and 'pushing' to make space for new values).
I created this function, but it returns 'NaN' every time:
function returnAverage(){
var averageArray = [];
var sum = 0;
var sampleEnd = values.length
for (var x = sampleEnd - 100; x < sampleEnd; x++) {
averageArray[x] = values[x]
}
for(var i = 0; i < averageArray.length; i++){
sum += parseInt(averageArray[i]);
}
var avg = sum/averageArray.length;
console.log(avg)
}
Any ideas?
If values is a array of numbers, last maximum 100 items average:
function returnAverage(values) {
var arr = values.slice(-100);
return arr.reduce(function(a, b){ return a + b; }, 0) / (arr.length || 1);
}
Issue number one is that the final value of sum and averageArray.lnegth is 0.
It seems this would happen because the "value" array is empty.
See example below:
var values = [0,1,2,3,4,5,6];
var averageArray = [];
var sum = 0;
var sampleEnd = values.length
for (var x = sampleEnd - 7; x < sampleEnd; x++) {
averageArray[x] = values[x]
}
for(var i = 0; i < averageArray.length; i++){
sum += parseInt(averageArray[i]);
}
var avg = sum/averageArray.length;
console.log(avg)
Edit: NaN is a result of division by zero. So you might want to check for that before calculating:
if(sum == 0 || averageArray.length == 0)
{
return 0;
}