'undefined' result for variable in Javascript function - javascript

something in my code is meaning that I am getting an array printed which contains only undefined values, not the random numbers I am expecting.
My code is below:
function List(max, min, numLists, numItems) {
this.max = max,
this.min = min,
this.numLists = numLists,
this.numItems = numItems,
this.generateLists = function () {
var fullArray = [];
var completeArray = [];
for (i = this.min; i < this.max; i++) {
fullArray.push(i);
}
for (i = 0; i < numItems; i++) {
var randomItem = Math.floor(Math.random() * (1 + (this.max - this.min)));
completeArray.push(fullArray[randomItem]);
}
console.log(completeArray);
}
}
var newList = new List(12, 100, 1, 15);
newList.generateLists();
The code is supposed to print a random list of number between the min and max values. I'm getting an array with 15 values in, but they are all undefined. I'm guessing this mean there is something wrong with my first 'for' loop?
If anyone has any suggestions on how I could make this better please do criticise!
Thanks in advance.

You have min and max mixed up in your arguments list. this results in an impossible boundary for your numbers (greater than 100 but less than 12). Just swap the parameters in the first line from max,min to min,max.
function List(min,max,numLists,numItems){
this.max = max,
this.min = min,
this.numLists = numLists,
this.numItems = numItems,
this.generateLists = function (){
var fullArray = [];
var completeArray = [];
for ( i = this.min ; i<this.max ; i++) {
fullArray.push(i);
}
for ( i = 0 ; i<numItems ; i++) {
var randomItem = Math.floor(Math.random() * (1+(this.max-this.min)));
completeArray.push(fullArray[randomItem]);
}
console.log(completeArray);
}
}
var newList = new List ( 12 , 100 , 1,15);
newList.generateLists();

I think you swap the position of max and min when you initiate newList.
Change the line to:
var newList = new List ( 100, 12 , 1,15);
Then it should work fine.

You were pushing fullArray[randomItem] that contains nothing. It is never initialized
function List(max, min, numLists, numItems) {
this.max = max,
this.min = min,
this.numLists = numLists,
this.numItems = numItems,
this.generateLists = function() {
var completeArray = [];
for (i = 0; i < numItems; i++) {
var randomItem = Math.floor(Math.random() * (1 + (this.max - this.min)));
completeArray.push(randomItem);
}
document.write(completeArray);
}
}
var newList = new List(12, 100, 1, 15);
newList.generateLists();

I think maybe you max and min arguments were in the wrong order. You were trying to access the fullArray with a negative index due to subtracting a larger number from a smaller one.
function List(min,max,numLists,numItems){
this.max = max,
this.min = min,
this.numLists = numLists,
this.numItems = numItems,
this.generateLists = function (){
var fullArray = [];
var completeArray = [];
for ( i = this.min ; i<this.max ; i++) {
fullArray.push(i);
}
for ( i = 0 ; i<numItems ; i++) {
var randomItem = Math.floor(Math.random() * (1+(this.max-this.min)));
console.log(randomItem)
completeArray.push(fullArray[randomItem]);
}
console.log(completeArray);
}
}
var newList = new List ( 12 , 100 , 1,15);
newList.generateLists();

I think max and min parameter are swapped
This
function List(max,min,numLists,numItems){
should be
function List(min,max,numLists,numItems){

Just replace this line;
var randomItem = Math.floor(Math.random() * (1+(this.max-this.min)));
with;
var randomItem = Math.floor(Math.random()*(fullArray.length)+1);

Related

JavaScript: Shuffling a deck, but it does NOT create a new shuffled deck each time using the original list

I am trying to shuffle a deck. I take a number of cards as input. For example, numCards = 5, so the deck (list) becomes [0,1,2,3,4]. The problem is that the while loop in the test_order(i,j,l) function is not shuffling properly. Function console.log(m) should print a new shuffled deck/list using the original list (l) but it keeps printing [0,1,2,3,4] after the first correct shuffle. It should create a newly shuffled deck each time using the original list, instead, it keeps repeating the original list or 1st shuffled list.
The purpose of the program is to find the probability of the number of times a card labeled i is above card labeled j after shuffles.
function list(numCards){
var newList = []
var i = 0;
while (i < numCards){
newList.push(i);
i++;
}
return newList
}
function top_to_random(l){
while(numPerformed != 0){
var x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift())
numPerformed--;
}
return l
}
function test_order(i,j,l){ //PROBLEM IS IN HERE!!!!
var n = 0
var trials = 10
var count = 0
while (count < trials){ // PROBLEM IN WHILE LOOP
let arrayCopy = JSON.parse(JSON.stringify(l));
//console.log(arrayCopy)
var m = top_to_random(arrayCopy)
m.indexOf(i) < m.indexOf(j) ? n++ : n = n + 0
//console.log(arrayCopy)
console.log(m)
count++
}
var prob = n/trials
return prob
}
//Argument Inputs
var numCards = parseInt(prompt("Enter number of cards in deck: "))
var l = list(numCards)
var numPerformed = parseInt(prompt("Enter number of shuffles to perform on deck: "));
var i = parseInt(prompt("i: "))
var j = parseInt(prompt("j: "))
//Execution
console.log(test_order(i,j,l))
Problem is not where you think it is, it's in your top_to_random function. You count the number of mixes done in your shuffle down from numPerformed, but this is a global-scope variable, so its not reset at each call. You should pass the mix count as a parameter like this:
function top_to_random(l, mixNum){
for (;mixNum > 0; mixNum--) {
var x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift());
}
return l;
}
Fixing a number of your syntax miconstructs, I get this code:
function list(numCards){
var newList = [];
var i = 0;
while (i < numCards){
newList.push(i);
i++;
}
return newList;
}
function top_to_random(l, mixNum){
for (;mixNum > 0; mixNum--) {
var x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift());
}
return l;
}
function test_order(i,j,l){ //Problem is NOT in here
let n = 0;
let trials = 10;
for (let count = 0; count < trials; count++) { // No not here
let arrayCopy = [...l];
top_to_random(arrayCopy, numPerformed);
console.log(arrayCopy)
if (arrayCopy.indexOf(i) < arrayCopy.indexOf(j)) n++;
console.log(arrayCopy);
}
var prob = n/trials;
return prob;
}
// Argument Inputs
var numCards = parseInt(prompt("Enter number of cards in deck: "));
var l = list(numCards);
var numPerformed = parseInt(prompt("Enter number of shuffles to perform on deck: "));
var i = parseInt(prompt("i: "));
var j = parseInt(prompt("j: "));
//Execution
console.log(test_order(i,j,l));
Also You should be more careful about details when you code:
You have a lot of missing semicolons
You're mixing function arguments and global variables with no logic to the decision
Don't use while when you should be using for
Ternary operator to perform a simple if ?
You'd better use const and let instead of var. For one thing it would have saved you this error
Better written code:
const SHUFFLE_REPEATS = 10;
function list(numCards) {
const newList = [];
for (let i = 0; i < numCards; i++)
newList.push(i);
return newList;
}
function top_to_random(l, mixNum) {
for (; mixNum > 0; mixNum--) {
const x = Math.floor(Math.random() * l.length);
l.splice(x, 0, l.shift());
}
return l;
}
function test_order(i, j, l) {
let n = 0;
for (let count = 0; count < SHUFFLE_REPEATS; count++) {
const arrayCopy = [...l];
top_to_random(arrayCopy, numPerformed);
console.log(arrayCopy)
if (arrayCopy.indexOf(i) < arrayCopy.indexOf(j)) n++;
}
return n / SHUFFLE_REPEATS;
}
// Argument Inputs
const numCards = parseInt(prompt("Enter number of cards in deck: "));
const l = list(numCards);
const numPerformed = parseInt(prompt("Enter number of shuffles to perform on deck: "));
const i = parseInt(prompt("i: "));
const j = parseInt(prompt("j: "));
//Execution
console.log(test_order(i,j,l));

Javascript for loop check condition

I want to create a function that will generate a random number between 0 to 9 which is not in the array.
My code so far:
var myArr = [0,2,3,4];
console.log("Arr: " + myArr);
function newNum(){
console.log("test");
for (var i = 0; i < 10; i++) {
var n = myArr.includes(i)
// I want to return n if it's not present in the array
}
return n;
}
newNum()
I want to return only 1 number. How do I do this?
Thanks.
What about this?
const invalidValues = [0,2,3,4];
const getRandomInt = (min, max) => {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
const getValidRandomInt = (min, max) => {
while(true) {
let temp = getRandomInt(min,max)
if(!invalidValues.includes(temp)) {
return temp;
}
}
}
console.log(getValidRandomInt(0,10))
var myArr = [0,2,3,4];
function newNum(){
for (var i = 0; i < 10; i++) {
if (!myArr.includes(i)) {
return i;
}
}
// return -1 if all numbers present in array..
return -1;
}
newNum();
Generate the number within the range by using Math.random() then loop and check whether the number generated is in the array or not, if not in the array return the number:
function getRandomArbitrary(min, max, arr) {
arr = new Set(arr);
while(true){
let val = Math.floor(Math.random() * (max - min) + min);
if(!arr.has(val)){ return val;}
}
}
console.log(getRandomArbitrary(0, 10, [4,3,2]));
Answer:
Use Math.random() * (max - min) + min to get a number within a range.
You can wrap it with Math.floor to round down to an integer, or alternatively use a bitwise OR ( | ) for small numbers.
function newNum(n_arr) {
let r = () => Math.random()*9 | 0,
n = r();
while(n_arr.includes(n)) {
n = r();
}
return n;
}
Example:
var myArr = [0,2,3,4];
function newNum(n_arr){
let r = () => Math.random()*9 | 0,
n = r();
while(n_arr.includes(n)) {
n = r();
}
return n;
}
let result = newNum(myArr);
console.log(result);
var myArr= [0,2,5];
function randomNumber(myArr, n){
n ? n : 1;
var num = Math.random() * n;
if(myArr.indexOf( num ) !==-1 ) {
return randomNumber( myArr, n );
}
return num;
}
randomNumber(myArr, 10);
If you want to return the first number missing in the array, from your code above, you could just check if every value of i exists in the array and the moment that value doesn't exist, return it.
var myArr = [0,2,3,4]; // original array
function newNum(){
for (var i = 0; i < 10; i++) { // loop through i from 0-9
if (myArr.indexOf(i) === -1){ // check for the first missing number
return i; //return it
}
}
}
newNum()

Issue with looping a function using a for loop

I'm having some issues with a for loop. When I run the code, the function seems to run once, as a random list is displayed, but not the expected number that is specified.
Can anyone help me out?
function List(max,min,numLists,numItems){
this.max = max,
this.min = min,
this.numLists = numLists,
this.numItems = numItems,
this.generateList = function (){
var fullArray = [];
var completeArray = [];
var numItems = this.numItems
//create an array of integers between min and max values
for ( i = this.min ; i<(this.max+1) ; i++) {
fullArray.push(i);
}
//select a random value from array of integers and add to new array
for ( j = 0 ; j<numItems ; j++) {
var randomItem = Math.floor(Math.random() * (fullArray.length));
completeArray.push(fullArray[randomItem]);
}
//write new random list
document.write(completeArray);
}
this.generateMultipleLists = function() {
var numLists = this.numLists;
//loop list creation to create multiple list arrays
for ( i=0 ; i<numLists ; i++ ){
this.generateList();
}
}
}
var newList = new List ( 100 , 12 , 7,15);
newList.generateMultipleLists();
Don't create global variables
In the function generateMultipleLists use var i in for loop instead of just i.

Repeated sequence of numbers in Javascript

I want to generate a vector of 100 values composed by [1 0]:
This is how I did it in Matlab:
n = 100;
Seq1 = [1 0]; % sequence of 1-0
Vector = repmat(Seq1,(n/2),1); % Creates n/2 sequences of 1-0
The result is a vector like: [1 0 1 0 1 0 1 0...]
Is there a way to get the same result with JavaScript?
You could mimic the function repmat with a while loop.
function repmat(array, count) {
var result = [];
while (count--) {
result = result.concat(array);
}
return result;
}
var nTrials = 100,
Seq1 = [1, 0],
Vector = repmat(Seq1, nTrials / 2);
console.log(Vector);
Assuming you're looking for a way to add a 1 and then a 0, not an array containing 1 and 0:
var myArray = [];
nTrials = 30;
for(i = 1; i<= nTrials/2; i++){
myArray.push(1);
myArray.push(0)
}
document.body.innerHTML = myArray[1];}
https://jsfiddle.net/6seqs6af/1/
FWIW, here is the full repmat implementation in JavaScript.
It uses arrow functions (=>) which isn't available in all browsers.
// Seq1 is an Array (1D vector). We need a Matrix which JavaScript doesn't have
// natively. But we can derive a Matrix type from an Array by adding
// `numberOfRows` and `numberOfColumns` properties as well as a `set` method
function Matrix(numberOfRows, numberOfColumns) {
this.numberOfColumns = numberOfColumns;
this.numberOfRows = numberOfRows;
this.length = numberOfColumns * numberOfRows;
this.fill();
}
Matrix.prototype = Array.prototype;
Matrix.prototype.set = function() {
for (var i = 0; i < arguments.length; i++) {
this[i] = arguments[i];
}
return this;
}
Matrix.prototype.toString = function() {
return this.reduce((acc, x, idx) => acc + (idx % this.numberOfColumns === this.numberOfColumns - 1 ? x + '\n' : x + ', '), '');
}
Matrix.prototype.at = function(row, column) {
return this[row * this.numberOfColumns + column];
}
// Repmap
// ======
function repmat(mat, repeatColumns, repeatRows) {
var numberOfColumns = mat.numberOfColumns * repeatColumns;
var numberOfRows = mat.numberOfRows * repeatRows;
var values = [];
for (var y = 0; y < numberOfRows; y++) {
for (var x = 0; x < numberOfColumns; x++) {
values.push(mat.at(y % mat.numberOfRows, x % mat.numberOfColumns));
}
}
var result = new Matrix(numberOfRows, numberOfColumns);
result.set.apply(result, values);
return result;
}
// Calculation
// ===========
var nTrials = 100;
var seq1 = new Matrix(1, 2);
seq1.set(1, 0);
var vector = repmat(seq1, nTrials / 2, 1);
console.log(vector.toString());

Not getting the correct value from JSON Array

I am getting NaN and Infinity in getting the max value of my JSON Array object.
I am trying to append the properties of a GeoJSOn data from other JSON.
Here's the JSFiddle for reference.
The snippet:
$.map(data, function (e) {
var dev_id = e.dev_id;
var data = e.data;
for (var j = 0; j < data.length; j++) {
var rainVal = parseFloat(data[j].rain_value);
arr[j] = parseFloat(rainVal);
}
var max = Math.max.apply(Math, arr) * 4;
console.log(dev_id + " " + max)
for (var k = 0; k < len; k++) {
jsonObj_device_id = jsonObj.features[k].properties["device_id"];
if (jsonObj_device_id === dev_id) {
var nameR = "rain_intensity";
var rainValue = max;
jsonObj.features[k].properties[nameR] = rainValue;
}
}
});
There are cases in your code, where in the AJAX response, you are either not getting the Data i.e. e.data or if you get the data you are not getting rain_value. If you do not get e.data first time, you will get Infinity logged on your console because var max = Math.max.apply(Math, []) results in -Infinity. If you do not get rain_value then parseFloat would give you NaN.
Validate the API response before such operations. Something like this.
var dev_id = e.dev_id;
var data = e.data;
var max = 0, r;
var arr = [];
if(data) {
for (var j = 0; j < data.length; j++) {
r = data[j].rain_value || 0;
arr[j] = parseFloat(r);
}
}
if(arr.length) {
max = Math.max.apply(Math, arr) * 4;
}
console.log(dev_id + " " + max);
Here is a working demo
var rainVal = parseFloat(data[j].rain_value);
if (!rainVal) // check 1
rainVal = 0;
arr[j] = parseFloat(rainVal);
}
var max = 0;
if (arr) // check 2
{
maxBeforeTested = Math.max.apply(Math, arr) * 4;
if (isFinite(maxBeforeTested)) //check 3
max = maxBeforeTested;
else
console.log("Had an infinite value here.");
}
console.log("Cleaned output: " + dev_id + " " + max)
Basically, you needed some checks, I have added comments as "Check".
Any number greater than 1.797693134862315E+308 is infinity. Use isFinite() to check.
NaN means not a number value, you can check that using isNaN() or simply if()

Categories

Resources