I am getting a random generated number between one and 10 from getRandom(1,10), but i do not want the same number twice.
To prevent that, I am saving the number I get inside an array used.
Now I want to check if the new number I get already is inside that array.
If not continue going,
if it is, then start over (get new number etc.).
What I am missing right now is the part where it should start over. Or should this work?
jQuery(document).ready(function($){
var i=0;
while (i<21){
var used = new Array(20);
for(a=0; a<20; a++) {
var number = getRandom(1, 20);
used[a] = number;
}
var tf = inArray(number,used);
//Check if number is inside the
if(tf==false){
//If not
i++;
}else{
//If it is
i--;
}
}
function inArray(Item,arr) {
for(p=0;p<arr.length;p++) {
if (arr[p]==Item) {
return true;
}
}
return false;
}
});
// create pool of numbers
var pool = [];
for (var i=1; i<=20; i++)
pool.push(i);
// pop off a random element of the array
var some_random_number = pool.splice(Math.floor(Math.random()*pool.length), 1)[0]
// repeat until pool is empty.
Related
I am trying to display up to three recipes from an API that specifically include bacon as an ingredient. The API only has 10 recipes that meet this criteria, so I am running into an issue where the same recipes are sometimes being repeated on the page if the user wishes to view two or three recipes. How can I set a condition to check if the random number that I am generating and storing in an array is a duplicate value? If a duplicate, then I want for the iterator to be subtracted by 1 and the for loop to continue. I've listed the code I've I appreciate any feedback that is provided!
// The number of recipes the user would like to display//
var recipeNumber = $("#recipe-input").val();
var parsedInput = parseInt(recipeNumber);
// creating an empty array that will story the random numbers that are generated//
var ranNumArr = [];
console.log(ranNumArr);
for (i = 0; i < parsedInput; i++) {
// generate a random number based on the length of the recipe API's array of bacon recipes (10) and push it into the ranNumArr//
var randomNumber = Math.floor(Math.random() * 10);
ranNumArr.push(randomNumber);
// If the value of the index in the array is equal to a previous index's value, repeat the iteration//
if (ranNumArr[i] === ranNumArr[i -1] || ranNumArr[i] === ranNumArr[i -2]){
console.log("this is a duplicate number")
i = i - 1
}
// else, display the recipe on the card//
else {
randomRecipe = ranNumArr[i]
// Create cards that will house the recipes//
var recipeCell = $("<div>").attr("class", "cell");
$("#recipes-here").append(recipeCell);
var recipeCard = $("<div>").attr("class", "card");
recipeCell.append(recipeCard);
var recipeSection = $("<div>").attr("class", "card-section");
recipeCard.append(recipeSection);
var cardTitleE1 = $("<h1>");
cardTitleE1.attr("id", "recipe-title");
var cardImageE1 = $("<img>");
cardImageE1.attr("id", "recipe-image");
var cardTextE1 = $("<a>");
cardTextE1.attr("id", "recipe-link");
// Adding the recipe title, url, and image from the API call//
cardTitleE1.text(response.hits[randomRecipe].recipe.label);
cardTextE1.text("Click here for link to recipe");
cardTextE1.attr("href", response.hits[randomRecipe].recipe.url);
cardTextE1.attr("target", "_blank");
cardImageE1.attr("src", response.hits[randomRecipe].recipe.image);
// Display the recipe on the DOM//
recipeSection.append(cardTitleE1);
recipeSection.append(cardImageE1);
recipeSection.append(cardTextE1);
}
}
You can use a Set to store numbers that have already been chosen.
const set = new Set;
//....
if (set.has(randomNumber)){
console.log("this is a duplicate number");
i--;
} else {
set.add(randomNumber);
//...
Alternatively, as Barmar suggested, you can shuffle the array of integers from 0 to 9 beforehand and then loop over the values for better efficiency. Below I have provided an example using the Fisher-Yates shuffle.
const arr = [...Array(10).keys()];
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.random() * (i + 1) | 0;
const temp = array[i];
array[i] = array[j];
array[j] = temp;
}
for(const num of arr){
//do something with num...
}
I'm working on exercism question and am stuck on one of the jasmine-node based tests, which says that I should be able to generate 10000 random names without any clashes (e.g. 2 randomly generated names match). This is the test:
it('there can be lots of robots with different names each', function() {
var i,
numRobots = 10000,
usedNames = {};
for (i = 0; i < numRobots; i++) {
var newRobot = new Robot();
usedNames[newRobot.name] = true;
}
expect(Object.keys(usedNames).length).toEqual(numRobots);
});
What I think I need to do is:
Create an array to hold all the names (robotNames),
Each time a name is generated, check if it exists in the array,
If it does, generate another name,
If it doesn't, add it to the array.
And here is my code so far...
"use strict";
var robotNames = [];
var name;
var Robot = function() {
this.name = this.generateName();
};
Robot.prototype.generateName = function() {
var letters = "";
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numbers = "";
var digits = "0123456789";
// generate random characters for robot name...
for( var i=0; i < 2; i++ ) {
letters += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
};
for( var i=0; i < 3; i++ ) {
numbers += digits.charAt(Math.floor(Math.random() * digits.length));
};
name = letters+numbers;
// Loop through array to check for duplicates
for(var i = 0; i < robotNames.length; i++) {
if (name == robotNames[i]) {
this.generateName();
return;
} else {
robotNames.push(name);
}
}
return name;
};
Robot.prototype.reset = function() {
this.name = this.generateName();
};
module.exports = Robot;
The test fails with an error message: "Expected 9924 to equal 10000."
The '9924' number is slightly different each time I run the test. I'm thinking this means the generateName function is eventually generating 2 matching random names. It seems as though my loop for checking duplicates is not being run and I'm not sure why.
I have tried a couple of different versions of the loop but with no success. So my questions is a) is my approach correct and there is something wrong with the syntax of my loop? or b) have I got the wrong idea about how to check for duplicates here?
Any pointers appreciated, thanks.
The problem is in this bit:
for(var i = 0; i < robotNames.length; i++) {
if (name == robotNames[i]) {
this.generateName();
return;
} else {
robotNames.push(name);
}
}
...you probably only want to push your name if NONE of the names fail to match. Here you're adding it to the list as soon as you find ONE that doesn't match. You want something more like:
for(var i = 0; i < robotNames.length; i++) {
if (name == robotNames[i]) {
return this.generateName();
}
}
robotNames.push(name);
(actually, combined with the fact that you weren't even returning the recursive call to this.generateName(), I'm not sure how your program could work...)
Find a library with an implementation for Sets. Collections.js is a good example.
One property of a set is that it doesn't have duplicates. So when you add a value to a set it will look for a duplicate and then add the value if no duplicate exists.
I'd like to build a text string by inserting the characters at random, but in place order (as a kind of effect) . So far I've got:
// make a string and an array
var input = "Hello, world!",
output = [];
// split the string
input = input.split('');
My idea is then to call this
function addAnElement(){
// check if there are any left
if(input.length){
// pick an element at random
var rand = Math.floor(Math.random() * input.length);
// remove it, so we don't call it again
var element = input.splice(rand,1);
// insert it
output[rand] = element;
// use the string returned as new innerHTML, for example
return output.join('');
// repeat until finished
setTimeout(addAnElement,5);
}
}
I'm hoping this would return something like:
'e'
'er'
...
'Hel, or!'
...
'Helo, Word!'
... and finally ...
'Hello, World!'
The problem, of course, is that the array is re-indexed when spliced - and this yields gibberish. I think the answer must be to link the elements to their positions in input and then insert them intact, sorting by key if necessary before returning.
How do I do this?
How about something like this:
var input = 'Hello world',
inputIndexes = [],
output = [];
for (var i = 0; i < input.length; i++) {
inputIndexes[i] = i;
};
function addAnElement() {
if (inputIndexes.length) {
var rand = Math.floor(Math.random() * inputIndexes.length);
var element = inputIndexes.splice(rand, 1);
output[element] = input[element];
//console.log(output.join(' '));
document.getElementById('text').innerHTML = output.join(' ');
setTimeout(addAnElement, 2000);
}
}
addAnElement();
http://jsfiddle.net/fg2ybz8j/
You can avoid it by not using splice. Instead, clear an entry when you've used it, and keep a count of the entries you've cleared.
E.g.:
var entriesLeft = input.length;
function addAnElement(){
// pick an element at random, re-picking if we've already
// picked that one
var rand;
do {
rand = Math.floor(Math.random() * input.length);
}
while (!input[rand]);
// get it
var element = input[rand];
// clear it, so we don't use it again
input[rand] = undefined;
// insert it
output[rand] = element;
// repeat until finished
if (--entriesLeft) {
setTimeout(addAnElement,5);
}
// use the string returned as new innerHTML, for example
return output.join('');
}
Of course, that loop picking a random number might go on a while for the last couple of characters. If you're worried about that, you can create a randomized array of the indexes to use up-front. This question and its answers address doing that.
Live Example:
var input = "Hello, there!".split("");
var output = [];
var entriesLeft = input.length;
function addAnElement() {
// pick an element at random, re-picking if we've already
// picked that one
var rand;
do {
rand = Math.floor(Math.random() * input.length);
}
while (!input[rand]);
// get it
var element = input[rand];
// clear it, so we don't use it again
input[rand] = undefined;
// insert it
output[rand] = element;
// repeat until finished
if (--entriesLeft) {
setTimeout(addAnElement, 5);
}
// use the string returned as new innerHTML, for example
document.body.innerHTML = output.join('');
}
addAnElement();
Side note: Notice how I've moved the call to setTimeout before the return. return exits the function, so there wouldn't be any call to setTimeout. That said, I'm confused by the need for the return output.join(''); at all; all calls but the first are via the timer mechanism, which doesn't care about the return value. In the live example, I've replaced that return with an assignment to document.body.innerHTML.
Here's a demonstration of the method that shuffles an array of indexes instead. It uses the shuffle method from this answer, but I'm not saying that's necessarily the best shuffle method.
function shuffle(array) {
var tmp, current, top = array.length;
if (top)
while (--top) {
current = Math.floor(Math.random() * (top + 1));
tmp = array[current];
array[current] = array[top];
array[top] = tmp;
}
return array;
}
var input = "Hello, there".split("");
var output = [];
var indexes = input.map(function(entry, index) {
return index;
});
shuffle(indexes);
var n = 0;
function addAnElement() {
// get this index
var index = indexes[n];
// get this loop's element
var element = input[index];
// insert it
output[index] = element;
// repeat until finished
if (++n < indexes.length) {
setTimeout(addAnElement, 5);
}
// use the string returned as new innerHTML, for example
document.body.innerHTML = output.join("");
}
addAnElement();
I'm am working on a script to count the number of times a certain string (in this case, coordinates) occur in a string. I currently have the following:
if (game_data.mode == "incomings") {
var table = document.getElementById("incomings_table");
var rows = table.getElementsByTagName("tr");
var headers = rows[0].getElementsByTagName("th");
var allcoord = new Array(rows.length);
for (i = 1; i < rows.length - 1; i++) {
cells = rows[i].getElementsByTagName("td");
var contents = (cells[1].textContent);
contents = contents.split(/\(/);
contents = contents[contents.length - 1].split(/\)/)[0];
allcoord[i - 1] = contents
}}
So now I have my variable allcoords. If I alert this, it looks like this (depending on the number of coordinates there are on the page):
584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519,,
My goal is that, for each coordinate, it saves how many times that coordinate occurs on the page. I can't seem to figure out how to do so though, so any help would be much appreciated.
you can use regular expression like this
"124682895579215".match(/2/g).length;
It will give you the count of expression
So you can pick say first co-ordinate 584 while iterating then you can use the regular expression to check the count
and just additional information
You can use indexOf to check if string present
I would not handle this as strings. Like, the table, is an array of arrays and those strings you're looking for, are in fact coordinates. Soooo... I made a fiddle, but let's look at the code first.
// Let's have a type for the coordinates
function Coords(x, y) {
this.x = parseInt(x);
this.y = parseInt(y);
return this;
}
// So that we can extend the type as we need
Coords.prototype.CountMatches = function(arr){
// Counts how many times the given Coordinates occur in the given array
var count = 0;
for(var i = 0; i < arr.length; i++){
if (this.x === arr[i].x && this.y === arr[i].y) count++;
}
return count;
};
// Also, since we decided to handle coordinates
// let's have a method to convert a string to Coords.
String.prototype.ToCoords = function () {
var matches = this.match(/[(]{1}(\d+)[|]{1}(\d+)[)]{1}/);
var nums = [];
for (var i = 1; i < matches.length; i++) {
nums.push(matches[i]);
}
return new Coords(nums[0], nums[1]);
};
// Now that we have our types set, let's have an array to store all the coords
var allCoords = [];
// And some fake data for the 'table'
var rows = [
{ td: '04.shovel (633|455) C46' },
{ td: 'Fruits kata misdragingen (590|519)' },
{ td: 'monster magnet (665|506) C56' },
{ td: 'slayer (660|496) C46' },
{ td: 'Fruits kata misdragingen (590|517)' }
];
// Just like you did, we loop through the 'table'
for (var i = 0; i < rows.length; i++) {
var td = rows[i].td; //<-this would be your td text content
// Once we get the string from first td, we use String.prototype.ToCoords
// to convert it to type Coords
allCoords.push(td.ToCoords());
}
// Now we have all the data set up, so let's have one test coordinate
var testCoords = new Coords(660, 496);
// And we use the Coords.prototype.CountMatches on the allCoords array to get the count
var count = testCoords.CountMatches(allCoords);
// count = 1, since slayer is in there
Use the .indexOf() method and count every time it does not return -1, and on each increment pass the previous index value +1 as the new start parameter.
You can use the split method.
string.split('517,594').length-1 would return 2
(where string is '584|521,590|519,594|513,594|513,590|517,594|513,592|517,590|517,594|513,590|519')
How can you, in using a random number generator, stop a number from appearing if it has already appeared once?
Here is the current code:
var random = Math.ceil(Math.random() * 24);
But the numbers appear more than once.
You can use an array of possible values ( I think in your case it will be 24 ) :
var values = [];
for (var i = 1; i <= 24; ++i){
values.push(i);
}
When you want to pick a random number you just do:
var random = values.splice(Math.random()*values.length,1)[0];
If you know how many numbers you want then it's easy, first create an array:
var arr = [];
for (var i = 0; i <= 24; i++) arr.push(i);
Then you can shuffle it with this little function:
function shuffle(arr) {
return arr.map(function(val, i) {
return [Math.random(), i];
}).sort().map(function(val) {
return val[1];
});
}
And use it like so:
console.log(shuffle(arr)); //=> [2,10,15..] random array from 0 to 24
You can always use an hashtable and before using the new number, check if it is in there or not. That would work for bigger numbers. Now for 24, you can always shuffle an array.
You could put the numbers you generate in an array and then check against that. If the value is found, try again:
var RandomNumber = (function()
{
// Store used numbers here.
var _used = [];
return {
get: function()
{
var random = Math.ceil(Math.random() * 24);
for(var i = 0; i < _used.length; i++)
{
if(_used[i] === random)
{
// Do something here to prevent stack overflow occuring.
// For example, you could just reset the _used list when you
// hit a length of 24, or return something representing that.
return this.get();
}
}
_used.push(random);
return random;
}
}
})();
You can test being able to get all unique values like so:
for(var i = 0; i < 24; i++)
{
console.log( RandomNumber.get() );
}
The only issue currently is that you will get a stack overflow error if you try and get a random number more times than the amount of possible numbers you can get (in this case 24).