0

I have to create an algorithm that must take this input: N, range (rMax and rMin value) and average. And in function of this, it must return N values (an array for example) whose average is average input value.

function createAverageValues(N,rMin,rMax,average){
    var averageValues = [];
    var j = 0;
    while(j<N){
        ....
        ....
        ....
        averageValues.push(...);
        j++;
    };
    return averageValues;
};    

Requirements:

  • N, rMin, rMax are integer input values;
  • Return values can be also float values with two decimal places (x.xx).
  • Whenever I use the algorithm, with the same input values, the returned values can be different. But their average must always be the one indicated in the input;
  • The returned values, can also be repeated several times. So can also use several times the same value. I only care that average of returned averageValues array is the one required.

Exemple 1


/**
N of values: 4;
Range: 3-7 (3 <= value <= 7);
Average: 5;

N = 4;
rMin = 3;
rMax = 7;
average = 5;
**/

var averageValues = createAverageValues(4,3,7,5);

One possible solution would be:

averageValues = [3,4,6,7];

Another possible solution would be:

averageValues = [6,4,4,6];

Etc...

Exemple 2


/**
N of values: 5;
Range: 0-12 (0 <= value <= 12);
Average: 6;

N = 5;
rMin = 0;
rMax = 12;
average = 6;
**/

var averageValues = createAverageValues(5,0,12,6);

One possible solution would be:

averageValues = [12,4,10,0,4];

Another possible solution would be:

averageValues = [10,8,11,0,1];

Etc...

Exemple 3


/**
N of values: 3;
Range: 9-15 (9 <= value <= 15);
Average: 12;

N = 3;
rMin = 9;
rMax = 15;
average = 12;
**/

var averageValues = createAverageValues(3,9,15,12);

One possible solution would be:

averageValues = [10,14,12];

Another possible solution would be:

averageValues = [11,11,14];

Another possible solution would be:

averageValues = [9.50,14.75,11.75];

Etc...

  • In the second example the N of values is 5 not 4 right? – achref Jun 23 '16 at 19:49
  • Is there a requirement that the average value not be used `n` times? – evan.oman Jun 23 '16 at 19:58
  • Is it required that the numbers be integers? – Robert Dodier Jun 23 '16 at 20:00
  • @achref N is variable. The algorithm must take this input: N, range (max and min value) and average. And in function of this, it must return N values whose average is avarage input value. – AstrovicApps Jun 23 '16 at 20:17
  • @evan058 no, the average value may be used n times. You can use any value belonging to the range. I only care that their average is the one required. – AstrovicApps Jun 23 '16 at 20:20
  • @RobertDodier They can be also float values with two decimal places (x.xx) – AstrovicApps Jun 23 '16 at 20:22
  • @astrovicApps yes but you wrote 4 then (a,b,c,d,e) which makes five. Just to say... – achref Jun 23 '16 at 20:27
  • @achref ah ok, I had not noticed, sorry. I correct it immediately. Thank you – AstrovicApps Jun 23 '16 at 20:30
  • @astrovicApps If you can have `n` items which are all the mean, then you can always just use the mean `n` times. As for the range, that doesn't really matter because the only way that the range can accommodate `n` items with a certain mean is if the mean is within that range. Thus this is a trivial task, unless you have other requirements. – evan.oman Jun 23 '16 at 21:05
  • @evan058 Sure, but that is only one possible solution. I need to create an algorithm which from time to time to return me n random values, whose average is that required. So not only n times the average value. – AstrovicApps Jun 23 '16 at 21:13
  • @astrovicApps That is a completely different requirement than the one specified in the question. Please edit the question to include your full set of requirements. – evan.oman Jun 23 '16 at 21:14
  • 1
    @evan058 If I could always use the value of the average, it did not make sense to create an algorithm :) That is certainly a possible solution. Ok, I try to improve the question with a full set of requirements. – AstrovicApps Jun 23 '16 at 21:51
  • @astrovicApps And that is why I asked for clarification. Looking forward to the edits :) – evan.oman Jun 23 '16 at 21:53
  • 1
    @evan058 ok, I edited the question. I hope it is more clear now ;) – AstrovicApps Jun 23 '16 at 22:39
  • "must return from time to time different values": what does this mean ??? –  Jun 23 '16 at 22:45
  • That every time I use the function createdAverageValues (), with the same inputs, it can return different values. Their average is, however, always the desired one, just as in the examples. – AstrovicApps Jun 23 '16 at 22:50
  • 1
    poorly formulated question and totally unclear what do u mean by "must return from time to time different values" – Yerken Jun 24 '16 at 02:28
  • @Yerken What is not clear? "must return from time to time different values" mean that every time I use the function createdAverageValues (), with the same inputs, it can return different values. Their average is, however, always the desired one, just as in the examples. – AstrovicApps Jun 24 '16 at 06:27

2 Answers2

0

Let me take a jab at it. I will just outline the algorithm which you can use:

Problems boils down to below:

avg = (a+b+....)/N

As avg and N is given you need to figure out what all the values you need so that: avg*N = (a+b+....)

As we know there should be N terms which should sum to avg*N. We can use recursion/dynamic programming to find out the numbers which sum up to avg * N.

It is same as subset sum problem where instead of the numbers you have been given a range.

noman pouigt
  • 906
  • 11
  • 25
  • Thank you for your suggestion. I tested with a subset sum algorithm, the problem is that sometimes I could have dozens of numbers, and in that case it takes a long time. Whereas I need a quicker solution. But thanks to your answer that I was inspired to create [my algorithm](http://stackoverflow.com/a/38146136/5811628) :) – AstrovicApps Jul 01 '16 at 13:06
0

After several attempts, I created an algorithm that acceptably and quickly solves my problem :)

    // It create an of values, in the range [_rMin , _rMax], each of which differs from the next 0.1
function createRangeValues(_rMin, _rMax) {
 var rangeValues = [];
 var value = _rMin;
 while (value < _rMax) {
  rangeValues.push(value);
  value = ((value * 10) + 1) / 10;
  console.log("value ---> " + value);
 };
 return rangeValues;
};

// shuffle array http://stackoverflow.com/a/2450976/5811628
function shuffle(array) {
 var currentIndex = array.length,
     temporaryValue,
     randomIndex;

 // While there remain elements to shuffle...
 while (0 !== currentIndex) {

  // Pick a remaining element...
  randomIndex = Math.floor(Math.random() * currentIndex);
  currentIndex -= 1;

  // And swap it with the current element.
  temporaryValue = array[currentIndex];
  array[currentIndex] = array[randomIndex];
  array[randomIndex] = temporaryValue;
 }

 return array;
}

function calculateNewRangeValue(rangeValues, sumRangeValues, averageValuesSum, rMin, rMax){
 // Now I modify each value on rangeValues, in such a way that
 // their average is equal to desired avg.
 // The modified value must however be a value in the range.
 var newRangeValues = [];
 for (var i in rangeValues) {
  var value = parseFloat(rangeValues[i] / sumRangeValues * averageValuesSum).toFixed(2);
  if((value >= rMin) && value <= rMax){
   newRangeValues.push(value);
  }else{
   console.log(value +" is out range " + rMin + " - " + rMax + ". Create a new createRangeValues()");
   return false;
  };
 }; 
 return newRangeValues;
};

function createAverageValues(X, N, rMin, rMax, avg) { 
 var averageValues = [];
 // Calculate the sum of the average values
 // avg = averageValuesSum/N ===> averageValuesSum = avg*N;
 var averageValuesSum = parseInt(avg) * parseInt(N);
 console.log("averageValuesSum ---> " + averageValuesSum);
  
 // Array of values, in the range [rMin , rMax]. That means: rangeValues = [rMin, rMin+0.1, rMin+0.2, ...., rMax]
 var rangeValues = createRangeValues(rMin, rMax);
 console.log("rangeValues ---> " + rangeValues);
  
 for (var k = 0; k < X; k++) {    
  // Create a shuffled array of rangeValues
  var rangeValuesShuffled = shuffle(rangeValues);
  // I need only N values
  rangeValuesShuffled = rangeValuesShuffled.slice(0, N);
  console.log(k + ") shuffled rangeValuesShuffled ---> " + rangeValuesShuffled);
  
  // Calculate the sum of the N values  
  var sumRangeValues = 0;
  for (var i in rangeValuesShuffled) {
   sumRangeValues = sumRangeValues + rangeValuesShuffled[i];
  };
  console.log(k + ") sumRangeValues ---> " + sumRangeValues);
  
  // Calculate new rangeValues
  var newRangeValues = calculateNewRangeValue(rangeValuesShuffled, sumRangeValues, averageValuesSum, rMin, rMax);
  
  if(!newRangeValues){   
   // I found a value out of range, therefore
   // repeat the cycle with other values
   k--;
  }else{
   console.log("new rangeValues, in which the avg is " + avg + " ---> " + newRangeValues);  
   // This is not needed, but I use it only to check if the average
   // of the values of the new array, is really equal to the desired avg
   var newRangeValuesSum = 0;
   for (var i in newRangeValues) {
    newRangeValuesSum = parseFloat(newRangeValuesSum) + parseFloat(newRangeValues[i]);
   };
   console.log(k +") new rangeValuesSum ---> " + parseFloat(newRangeValuesSum).toFixed(2) + " ---> so avg is: " + parseFloat(newRangeValuesSum).toFixed(2)/N);
   console.log("********\n\n\n");  
     
   averageValues.push(newRangeValues);
   
   // Write results
   document.write("<br> averageValues["+k+"] ---> <br>" + averageValues[k].join("; "));
   document.write("<br> averageValuesSum["+k+"] ---> " + parseFloat(newRangeValuesSum).toFixed(2) + " ===> so avg is: " + parseFloat(parseFloat(newRangeValuesSum).toFixed(2)/N).toFixed(2)+"<br><br>");
  };
 }; 
 
 return averageValues;
};

/**
// HOW TO USE IT
// createAverageValues(X, N, rMin, rMax, avg);

X = Number of array of N values;
N = Number of values for each array;
rMin = min value of the range;
rMax = max value of the range;
avg = average of each array values

For example if I want 8 array of 10 values included in a range between 3 and 9, in which the average is 7:
createAverageValues(8, 10, 3, 9, 7);

**/

var averageValues = createAverageValues(8, 10, 3, 9, 7);
console.log("********\n\n\n averageValues:");
console.log(averageValues);