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.
Related
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));
I'm working from the solution provided HERE to compare two arrays. The example provided returns values found in both arrays to Array1 (same) and values only found on one or the other two Array2 (diff).
ISSUE: When I apply it to my own script, valuesDATA returns nothing and valuesCheckSeeding returns ALL values from both arrays
DESIRED RESULT: I have two arrays that I'd either like to create a third out of, or only select values from the first array, valuesDATA which are NOT present in the second, valuesCheckSeeding. Using the solution above, I was trying to have all values not found in valuesCheckSeeding AND valuesDATA pushed to valuesDATA.
SAMPLE OF valuesDATA: "U09 F
Harford FC Hill/Healey - A
MD
CMSA Girls Saturday U09 A/B North
Premier - Top
TID0118"
What am I doing wrong? I tinkered with changing matchfound==false and matchfound=true in the loop, but that still didn't give me the desired result.
MOST RELEVANT SNIPPET
var matchfound = false;
for (var i = 0; i < valuesDATA.length; i++) {
matchfound=false;
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i] == valuesCheckSeeding[j]) {
valuesCheckSeeding.splice(j, 1);
matchfound=true;
continue;
}
}
if (matchfound==false) {
valuesCheckSeeding.push(valuesDATA[i]);
valuesDATA.splice(i, 1);
i=i-1;
}
}
WORKIG SCRIPT EDITED FROM COMMENTS/ANSWERS BELOW
//UPDATE SEEDING SHEET
function updateSeedingSheet() {
var today = Utilities.formatDate(new Date(),Session.getScriptTimeZone(), "MM/dd/yyyy hh:mm a");
//INPUT SHEET INFO
var inputCurrentRow = 4;
var inputCurrentColumn = 20;
var inputNumRows = 1000;
var inputNumColumns =1;
var ssInput = SpreadsheetApp.openById('1Wzg2BklQb6sOZzeC0OEvQ7s7gIQ07sXygEtC0CSGOh4');
var sheetDATA = ssInput.getSheetByName('DATAREF');
var rangeDATA = sheetDATA.getRange(inputCurrentRow, inputCurrentColumn, inputNumRows, inputNumColumns);
var valuesDATA = rangeDATA.getValues();
//SEEDING SHEET INFO
var seedingCurrentRow = 4;
var seedingCurrentColumn = 1;
var seedingNumRows = 1000;
var seedingNumColumns = 1;
var ssSeeding = SpreadsheetApp.openById('1DuCHeZ3zba-nHq-7vYTrylncPGqcA1J9jNyW9DaS3mU');
var sheetSeeding = ssSeeding.getSheetByName('Seeding');
var rangeCheckSeeding = sheetSeeding.getRange(4, 102, 1000, 1);
var columnToClear = sheetSeeding.getRange(seedingCurrentRow, seedingCurrentColumn, seedingNumRows, seedingNumColumns);
var valuesCheckSeeding = rangeCheckSeeding.getValues();
//METHOD TO FILTER
valuesCheckSeeding = valuesCheckSeeding.map(function(e){return e[0];}); //flatten this array
var filteredArr = valuesDATA.filter(function(e){
return !(this.indexOf(e[0])+1);
},valuesCheckSeeding);
Logger.log(filteredArr);
Logger.log(filteredArr.length);
var rangeSeeding = sheetSeeding.getRange(seedingCurrentRow, seedingCurrentColumn, filteredArr.length, seedingNumColumns);
sheetSeeding.getRange('A1').setValue(today);
columnToClear.clearContent();
rangeSeeding.setValues(filteredArr);
/*
//ALTERNATIVE METHOD USING LOOPS
for (var i = 0; i < valuesDATA.length; i++) {
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i][0] == valuesCheckSeeding[j][0]) {
valuesDATA.splice(i, 1);
i--; //account for the splice
break; //go to next i iteration of loop
}
}
}
Logger.log("VALUES DATA:" + valuesDATA);
Logger.log("VALUES CHECK SEEDING: " + valuesCheckSeeding);
//sheetSeeding.getRange('A1').setValue(today);
//rangeSeeding.clearContent();
//rangeSeeding.setValues(valuesDATA); //INCORRECT RANGE HEIGHT, WAS 71 BUT SHOULD BE 1000 - Is splice affecting this?
*/
}//END FUNCTION
V8(ES2016 update):
You can use newer and efficient set class
const array1 = [[1],[2],[3]],
array2 = [[1],[3],[4]],
set = new Set(array2.flat())
console.info(array1.filter(e => !set.has(e[0])))
//expected output [[2]]
You're checking a 2D array. You'd need to use [i][0] and [j][0]
You can try only splicing valuesDATA
Try
for (var i = 0; i < valuesDATA.length; i++) {
for (var j = 0; j < valuesCheckSeeding.length; j++) {
if (valuesDATA[i][0] == valuesCheckSeeding[j][0]) {
valuesDATA.splice(i, 1);
i--; //account for the splice
break; //go to next i iteration of loop
}
}
}
Logger.log(valuesDATA);
Alternatively, try
valuesCheckSeeding = valuesCheckSeeding.map(function(e){return e[0];}); //flatten this array
var filteredArr = valuesDATA.filter(function(e){
return !(this.indexOf(e[0])+1);
},valuesCheckSeeding);
Logger.log(filteredArr);
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);
The following code is finding the largest number and if exist any value then i want to add it with one why i need this i want to store unique value
var xmlDoc=xmlHttpRequest.responseXML;
var recordSet = xmlDoc.getElementsByTagName("RECORD");
for(var j=0;j<recordSet.length;j++)
{
expNbrVal[j] = recordSet[j].getElementsByTagName("COL")[0].firstChild.data;
}
largest = expNbrVal[0];
for(var jc=1;jc<expNbrVal.length;jc++)
{
if(parseInt(expNbrVal[jc])>parseInt(largest))
{
largest = expNbrVal[jc];
}
}
if(recordSet.length>0)
{
var expval = parseInt(largest);
document.getElementById("expenseNbr").value = expval+1;
}
else
{
document.getElementById("expenseNbr").value =1;
}
expNbrVal.length =0;
I don't know the original code and you are using some already existing values so i don't know if this works, But this is what I would make from it.
Array.max = function( array ){
return Math.max.apply( Math, array );
};
var array = [];
var xmlDoc=xmlHttpRequest.responseXML;
var recordSet = xmlDoc.getElementsByTagName("RECORD");
if(recordSet.length>0) {
for(var j=0; j<recordSet.length; j++) {
array.push(parseInt(recordSet[j].getElementsByTagName("COL")[0].firstChild.data));
}
var largest = Array.max(array);
}else{
var largest = 0;
}
document.getElementById("expenseNbr").value = largest + 1;
I am using JQuery to calculate some totals figures and I have run into a problem.
Let's say I have two sets of inputs, each with a unique name.
$('[name="quantity\\[\\]"]')
$('[name="price\\[\\]"]')
I want to cycle through each set of inputs at the same time so that I can check both for (!isNaN) and (length !== 0), and if the values are valid, I want to multiply them together and add to a running total.
I know I can cycle through one selector using each(), but how can I cycle through two at the same time? is there an elegant way to accomplish this goal?
All cute things jQuery aside, here is a generic "zip" function.
a and b should be arrays (or at least array-like). If fn is supplied this will act as a map over each pair of items. Remember that jQuery objects are arrays.
function zip (a, b, fn) {
var len = Math.max(a.length, b.length)
var result = []
if (fn) {
for (var i = 0; i < len; i++) {
result.push(fn(a[i], b[i]))
}
} else {
for (var i = 0; i < len; i++) {
result.push([a[i], b[i]])
}
}
return result
}
Example:
var z = zip([1,2,3], ['a','b'])
// z = [[1,'a'],[2,'b'],[3,undefined]
for (var i = 0; i < z.length; i++) {
var elm = z[i]
var a = elm[0]
var b = elm[1]
alert(a + "-" + b)
}
Example with fn:
zip([1,2,3], ['a','b'], function (a, b) {
alert(a + "-" + b)
})
Example in jQuery'ish context:
var total = 0
zip(
$('[name="quantity\\[\\]"]'),
$('[name="price\\[\\]"]'),
function (a, b) {
// if either a or b are undefined, there is already a problem
// the `expr || 0` is to silently handle cases of `NaN || 0` which may
// result if the price or quantity are garbage values
var qty = parseInt($(a).val(), 10) || 0
var price = parseInt($(b).val(), 10) || 0
total += qty * price
})
Happy coding.
Here's a straight forward solution
var quantities = $('[name="quantity\\[\\]"]'),
prices = $('[name="price\\[\\]"]');
var len = Math.max(quantities.size(), prices.size());
for (var i=0; i < len; i++) {
var quantity = quantities.get(i);
var price = prices.get(i);
// Do whatever you want with quantity and price
}
Store the result of the selection in a variable, and use the index argument for the each when enumerating to reference the related element in the other set.
var quan = $('[name="quantity\\[\\]"]');
var price = $('[name="price\\[\\]"]');
var total = 0;
quan.each(function( index ) {
var quan_val = +$(this).val();
var price_val = +price.eq( index ).val();
if( quan_val && price_val ) {
total += (quan_val * price_val);
}
});
alert( total );
How about this:
function getValue() { return this.value; }
var valsA = $('input[name="quantity\\[\\]"]').map(getValue).get(),
valsB = $('input[name="price\\[\\]"]').map(getValue).get();
for ( var i = 0; i < valsA.length; i++ ) {
// work with valsA[i] and valsB[i] here
}
var prices = $('[name="price\\[\\]"]');
$('[name="quantity\\[\\]"]').each(function(i){
var quantity = this;
var price = prices[i];
// Compare them here.
});
Use a comma:
$('[name="quantity\\[\\]"], [name="price\\[\\]"]')
loop and use the index
var quantity = $('[name="quantity\\[\\]"]')
$('[name="price\\[\\]"]').each( function(ind){
var currentPrice = $(this);
var currentQuantity = quantity.eq(ind);
});
or something like
$('[name="price\\[\\]"]').each( function(ind){
var currentPrice = $(this);
var currentQuantity = currentPrice.closest('[name="quantity\\[\\]"]');
});