Sorting and Median with Arrays in Javascript - javascript

I have been working on this code, and the goal is to sort out the numbers in the array, and then find the median. My median isn't outputting correctly, and when I try to just see what is in array[0], it never has the right value. I'm not exactly sure where I messed up.
Code:
var array = [];
window.onload = function (){
var answer = '';
var median = 0;
for (var i = 0; i < 8; i++) {
var rand = Math.floor(Math.random() * 101);
array.push(rand);
array.sort(function(a, b){return a-b});
answer = answer + array[i] + " ";
}
median = ((array[3] + array[4]) /2);
document.getElementById("result").innerHTML = answer + "<br />" + median;
}

I would suggest first moving your loops ending. Currently you are sorting every single time you add a new number to the array. This means two things : you are wasting computation power on something you should only do once and when you 'log' your result in the line answer = answer + array[i] + " "; its constantly changing since the order is changing. Your functions logic is correct so by making the change below you should get the result you want.
var array = [];
window.onload = function (){
var answer = '';
var median = 0;
//Loop is simplified to just push a random value
for (var i = 0; i < 8; i++) {
array.push(Math.floor(Math.random() * 101));
}
//Sort is outside of the loop;
array.sort(function(a, b){return a-b});
//Median is outside of the loop
median = ((array[3] + array[4]) /2);
//answer is outside of the loop (if you don't know reduce look at the link below)
answer = array.reduce( function ( answer , value ) {
return answer + ',' + value;
} );
// put into the dom
document.getElementById("result").innerHTML = answer + "<br />" + median;
}
If you need help with this feel free to message me, also checkout the documentation for reduce HERE.

Using purely SO posts, I came up with a solution.
Strategy
Shuffle
At first, the partial expression (Math.floor(Math.random() * 101)) came up with duplicates, that's weaksauce. Fisher-Yates (aka Knuth) Shuffle has an excellent algorithm.
Your var answer and reduce expression is now combined and out of the loop as per #hyphnKnight explained. There's no need to break it down any further because reduce return is everything you need to display a sorted array. I also used unshift instead of push, I read that it's faster to use the front of the array rather than the back, but you can't tell the difference, too small of a function and all.
Snippet
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>35469092</title>
</head>
<output id="result"></output>
<body>
<script>
// 1. Populate an array with the numbers 1 through 100.
var arr = [];
for(var i = 1; i <= 100; i++) {
arr.unshift(i);
}
median(arr);
function median(arr){
var median = 0;
// 2. Shuffle
var ran100 = shuffle(arr);
var ran8 = [];
for(var j = 0; j < 8; j++) {
// Take the first 8 elements of the resulting array.
ran8.unshift(ran100[j]);
}
var answer = ran8.sort(function(a, b){return a-b});
median = ((ran8[3] + ran8[4]) /2);
document.getElementById("result").innerHTML = answer + "<br />" + median;
}
function shuffle(arr) {
var curIdx = arr.length, tmpVal, randIdx;
while (0 !== curIdx) {
ranIdx = Math.floor(Math.random() * curIdx);
curIdx -= 1;
tmpVal = arr[curIdx];
arr[curIdx] = arr[ranIdx];
arr[ranIdx] = tmpVal;
}
return arr;
}
</script>
</body>
</html>

Related

How do I use a for-loop to add values to a JS variable? [duplicate]

This question already has answers here:
How to add two strings as if they were numbers? [duplicate]
(20 answers)
Closed 4 years ago.
I have made a piece of code that generates a random code of 12 characters. I am using Math.random and for-loops to do this. On the page you can write in an input how many codes you want.
What I want to do is save the generated codes in an array, however I can't do this because the for-loop and Math.random creates the code number by number and places them after each other. How can I add the whole 12 digit code to my array (so I can use it later)?
I've tried array.push with no luck. What works is outputting the numbers to DOM object in HTML, like this:
for (i = 0; i < 12; i++) {
var mathRandom = Math.floor(Math.random() * 9);
var result = document.querySelector("#result");
result.innerHTML += mathRandom;
}
But that doesn't put the 12 digit code into a variable. I've also tried this:
var codeNumber = "";
codeNumber += mathRandom;
But that ends up in the variable value having only 1 digit.
<input type="number" id="numberOfCodes">
<button onclick="codeGen()">Generate</button>
<div id="result"></div>
<script>
var numberOfCodes = document.querySelector("#numberOfCodes");
var arr = [];
function codeGen() {
x = numberOfCodes.value;
for (a = 0; a < x; a++) {
generate();
console.log("Generated code");
}
}
function generate() {
for (i = 0; i < 12; i++) {
var mathRandom = Math.floor(Math.random() * 9);
var result = document.querySelector("#result");
result.innerHTML += mathRandom;
}
}
</script>
</div>
</body>
</html>
I expect the codes created (after some changes) to be added to the array, so that I can later use the codes on the page. Each individual 12-digit code needs to have its own place in the array.
This should work:
var result = [], stringResult;
for (i = 0; i < 12; i++) {
var mathRandom = Math.floor(Math.random() * 9);
result.push(mathRandom);
}
stringResult = result.join(''); // concatenates all the elements
console.log(stringResult);
The problem with your code is that + sign attempts to determine types of the operands and to choose the right operation, concatenation or addition. When adding stuff to innerHtml it treats the number as string. That is why it worked.
You'll want to refactor things so generating a single code is encapsulated in a single function (generate() here), then use that function's output, like this. (I hope the comments are enlightening enough.)
var numberOfCodes = document.querySelector("#numberOfCodes");
var resultDiv = document.querySelector("#result");
function codeGen() {
var nToGenerate = parseInt(numberOfCodes.value);
for (var a = 0; a < nToGenerate; a++) {
var code = generate(); // generate a code
// you could put the code in an array here!
// for the time being, let's just put it in a new <div>
var el = document.createElement("div");
el.innerHTML = code;
resultDiv.appendChild(el);
}
}
function generate() {
var code = ""; // define a local variable to hold the code
for (i = 0; i < 12; i++) { // loop 12 times...
code += Math.floor(Math.random() * 9); // append the digit...
}
return code; // and return the value of the local variable
}
<input type="number" id="numberOfCodes" value=8>
<button onclick="codeGen()">Generate</button>
<div id="result"></div>
As this answer shows, this should work for you:
function makeRandCode() {
var code = "";
var ints = "1234567890";
for (var i = 0; i < 12; i++) {
code += ints.charAt(Math.floor(Math.random() * ints.length));
}
return code;
}
console.log(makeRandCode());
The problem is that you are adding numbers and what you really want is to concatenate them, the solution is to transform those numbers into String, then save them in the variable where you want to store them. An example:
2 + 2 = 4 and '2'+'2'='22'
Just use .toString() before save it in to the variable.

Putting method with loop doesnt work

I'm trying to inserting the values of counter into an array called numpay.Unfortunately nothing happens.Where's my mistake?Here's what i tried below.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example-1</title>
</head>
<body>
<p id="demo"></p>
<script>
function validateForm() {
var months=(principal+principal*interestrate*0.01)/monthlypayment;
var numpay = new Array(months);
for(var i=0;i<=months-1;i++)
{
numpay.push(i);
text += numpay[i] + "<br>";
}
document.getElementById("demo").innerHTML = text;
}
</script>
</body>
</html>
Fixing existing problems
As others have pointed out, something like this should work:
var months = 12;
var numpay = []; // just as easy
var text = "";
for (var i = 1; i <= months; i++) {
numpay.push(i);
text += numpay[i - 1] + "<br/>";
}
document.getElementById('demo').innerHTML = text;
<p id="demo">(empty)</p>
Enhancing your skills
Although you're combining them in your for-loop, you're doing two separate things here: filling out the months, and creating the text you want to add to the DOM.
There's a lot to be said for one bit of code doing only one thing. You could write a reusable range function which uses more modern JS techniques to give you a numeric integer range between two values. So
const range = (lo, hi) => [...new Array(hi - lo + 1)].map((_, i) => i + lo);
Using that, you can create your months variable by calling this function:
const months = range(1, 12);
Then, with this array, you can use Array.prototype.join to combine the values into the text you would like:
const text = months.join('<br/>')
And that leads to a nicer bit of code:
const range = (lo, hi) => [...new Array(hi - lo + 1)].map((_, i) => i + lo);
const months = range(1, 12);
document.getElementById('demo').innerHTML = months.join('<br/>');
<p id="demo">(empty)</p>
If you need that text variable for something additional, then just assign it as the result of the join, and then assign the innerHTML to it.
Obviously that range function is unnecessary. You could just write const months = [...new Array(12)].map((_, i) => i + 1);. But thinking in terms of such abstractions often lets you write cleaner code.
1.) By creating an array like that (new Array(12)) you are saying to create 12 undefined entries in the array. Then you are pushing to the end of the array.
2.) You also need to initialize text with months var months = 12, text;.
var months = 12, text;
var numpay = new Array(months);
for(var i=1; i<=months; i++){
numpay[i] = i;
text += numpay[i] + "<br>";
}
document.getElementById("demo").innerHTML = text;
This will still give you undefined at index 0 but I will leave that for you to work out. But doing numpay[i] = i will overwrite your undefined that was created with the array.
Arrays in JS are zero-based, so if you do .push(i) with i === 1, the value 1 goes into the slot for numpay[0].
And then to access that item, you must use numpay[i-1].
Another thing is that you seem to have forgotten to declare and initialize text before the loop starts. You need to do that, if not then the variable only exists inside the loop body (and loses its value each time the loop body ends).
Demo:
var months = 12;
var numpay = []; // just as easy
var text = "- ";
for (var i = 1; i <= months; i++) {
numpay.push(i);
text += numpay[i - 1] + " - ";
}
console.log(text);
When you instantiate an array with a parameter like this:
var numpay = Array(12);
it results in an array with 12 undefined elements. When you push a new item, it will be placed in the 13th slot.
Instead, just do this:
var text = "";
var months=12;
var numpay = [];
for(var i=1;i<=months;i++)
{
numpay.push(i);
text += numpay[i-1] + "<br>"; //use i-1 here, not i
}
document.getElementById("demo").innerHTML = text;
The result is:
"1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11<br>12<br>"

subSetSum - powerSum JS . concatenating arrays into subset

With my very poor js knowledge, I am trying to solve the powerSum algorithm.Where I am supposed to return the count of the ways a number X can be expressed as the sum of the Nth powers of unique, natural numbers...
I have -somehow- got to the point where I can see my subsets printed out on the console but I haven't been able to figure out how to concatenate the result of my 'subsetSum' function to my 'subsets' variable so I can return my result as an array of arrays. The only way I get to have any returning value is if I concat my subsets into a STRING. and that is not what I am expecting. Here is my code.
// returns an array with all the results of natural numbers elevated
//to the nth power <= X
function powersLessThan(x,power){
let newArr = [];
for(var i = 1; i < x; i+=1){
var powered = Math.pow(i,power);
if (powered <= x){
newArr.push(powered);
}else if (powered > x){
break;
}
}
return newArr;
}
// returns an array of all the possible combinations of numbers that sum to X
function subsetsSum(numbersArr,target,partialSum){
var sum,n,remaining;
var subsets = [];
partialSum = partialSum || [];
sum = partialSum.reduce(function (a,b){
return a + b;
},0);
if (sum === target){
return partialSum; // this is my base case. datatype = object. Not sure why... ??
}
for (var i = 0; i < numbersArr.length; i+=1){
n = numbersArr[i];
remaining = numbersArr.slice( i + 1);
subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
}
return subsets;
}
console.log(subsetsSum(powersLessThan(100,2),100)); // with this my ooutput
is ' 1,9,16,25,4936,64100' instead of => [[1,9,16,25,49],[64,36],[100]] :/
The final count will be the length of the array above .. when it works..
Thanks for your help.
Change:
return partialSum;
To:
return [partialSum];
And change:
subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
To:
subsets = subsets.concat((subsetsSum(remaining,target,partialSum.concat([n]))));
(You could also just use, subsets.push(...))

Finding average from input array with Javascript - not calculating correctly

I am trying to calculate the average of 3 values (each numbered from 1-10) that are selected by the user and then pass the results to an text input (for display as a graph).
It should be updating the new average every time one of the values is changed, but the averaging is not working correctly at all. I think that the loop is not resetting the values every time it runs- it's adding up the sum each time it runs, but not sure how to fix it.
Here is my code:
var sliders = $("#health1,#health2,#health3");
var elmt = [];
$(sliders).each(function () {
elmt.push($(this).attr('value'));
$("#health1,#health2,#health3").change(function () {
var sum = 0;
averageRisk();
});
});
function averageRisk() {
var sum = 0;
for (var i = 0; i < elmt.length; i++) {
sum += parseInt(elmt[i], 10);
}
var avg = sum / elmt.length;
document.getElementById('healthLevel').value = +avg;
elmt.push($(sliders).attr('value'));
$('#healthLevel').val(avg).trigger('change');
console.log("Sum: " + sum);
console.log("Average: " + avg);
}
Here is an example:
http://jsfiddle.net/pixelmix/783cfmnv/
Not sure but seems like a lot of extra work going. Main issue was you were building array of initial values and not getting the values each time they changed. That first .each got all the slider values and added them to elmt and continued to push new values on to after every change instead of just getting the current values every time. Did you want to accumulate all values over time?
Fiddle: http://jsfiddle.net/AtheistP3ace/783cfmnv/6/
$("#health1,#health2,#health3").on('change', function () {
averageRisk();
});
function averageRisk() {
var sum = 0;
var elmt = $("#health1,#health2,#health3");
for (var i = 0; i < elmt.length; i++) {
sum += parseInt(elmt[i].value, 10); //don't forget to add the base
}
var avg = sum / elmt.length;
document.getElementById('healthLevel').value = +avg;
$('#healthLevel').val(avg).trigger('change');
console.log("Sum: " + sum);
console.log("Average: " + avg);
}
And as pointed out if you want to ignore updating things when the sum is NaN you can do this:
function averageRisk() {
var sum = 0;
var elmt = $("#health1,#health2,#health3");
for (var i = 0; i < elmt.length; i++) {
sum += parseInt(elmt[i].value, 10); //don't forget to add the base
}
if (isNaN(sum)) {
return false;
}
var avg = sum / elmt.length;
document.getElementById('healthLevel').value = +avg;
$('#healthLevel').val(avg).trigger('change');
console.log("Sum: " + sum);
console.log("Average: " + avg);
}
The problem is that you fill the elmt array at page loading.
When user changes the values, you do not refresh the elmt array. So the array used to compute the average is always the same, empty.
You have to recover the input values each time they are modified.
function averageRisk() {
var sum = 0;
// Re make the loop for getting all inputs values
$(sliders).each(function() {
var value = parseInt($(this).val(), 10);
sum += value;
});
var avg = sum/$(sliders).length;
$('#healthLevel').val(avg);
}
Working example : http://jsfiddle.net/783cfmnv/7/
PS : You can use the css class healthInput to select your inputs. If you add later other fields, you will not have to add the new input id to your jQuery selector.
I did this work, check it .
http://jsfiddle.net/783cfmnv/10/
$("#health1,#health2,#health3").change(function() {
var val1 = +slider1.val();
var val2 = +slider2.val();
var val3 = +slider3.val();
var avg = (val1 + val2 + val3) /3;
$("#healthLevel").val(avg);
});

How to get a unique random integer in a certain range for every number in that range in javascript?

I have:
function getRandomInt(min, max){
return Math.floor(Math.random() * (max - min + 1)) + min;
}
But the problem is I want randomise the population of something with elements in an array (so they do not appear in the same order every time in the thing I am populating) so I need to ensure the number returned is unique compared to the other numbers so far.
So instead of:
for(var i = 0; i < myArray.length; i++) {
}
I have:
var i;
var count = 0;
while(count < myArray.length){
count++;
i = getRandomInt(0, myArray.length); // TODO ensure value is unique
// do stuff with myArray[i];
}
It looks like rather than independent uniform random numbers you rather want a random permutation of the set {1, 2, 3, ..., N}. I think there's a shuffle method for arrays that will do that for you.
As requested, here's the code example:
function shuffle(array) {
var top = array.length;
while (top--) {
var current = Math.floor(Math.random() * top);
var tmp = array[current];
array[current] = array[top - 1];
array[top - 1] = tmp;
}
return array;
}
Sometimes the best way to randomize something (say a card deck) is to not shuffle it before pulling it out, but to shuffle it as you pull it out.
Say you have:
var i,
endNum = 51,
array = new Array(52);
for(i = 0; i <= endNum; i++) {
array[i] = i;
}
Then you can write a function like this:
function drawNumber() {
// set index to draw from
var swap,
drawIndex = Math.floor(Math.random() * (endNum+ 1));
// swap the values at the drawn index and at the "end" of the deck
swap = array[drawIndex];
array[drawIndex] = array[endNum];
array[endNum] = swap;
endNum--;
}
Since I decrement the end counter the drawn items will be "discarded" at the end of the stack and the randomize function will only treat the items from 0 to end as viable.
This is a common pattern I've used, I may have adopted it into js incorrectly since the last time I used it was for writing a simple card game in c#. In fact I just looked at it and I had int ____ instead of var ____ lol
If i understand well, you want an array of integers but sorted randomly.
A way to do it is described here
First create a rand function :
function randOrd(){
return (Math.round(Math.random())-0.5); }
Then, randomize your array. The following example shows how:
anyArray = new Array('1','2','3','4','5');
anyArray.sort( randOrd );
document.write('Random : ' + anyArray + '<br />';);
Hope that will help,
Regards,
Max
You can pass in a function to the Array.Sort method. If this function returns a value that is randomly above or below zero then your array will be randomly sorted.
myarray.sort(function() {return 0.5 - Math.random()})
should do the trick for you without you having to worry about whether or not every random number is unique.
No loops and very simple.

Categories