I want to get random names from the nameArray and each time delete that element, so that in the end, I have got all names and the nameArray is empty. Nothing displays in the console.
let i;
let nameArray = ['Chara','Lisette','Corine','Kevin','Carlee'];
while(i < nameArray.length){
let name = nameArray[ Math.floor( Math.random() * nameArray.length )];
console.log(name);
delete nameArray[i];
}
i is never initialized nor updated, so the while loop doesn't make too much sense.
You can try this instead:
let nameArray = ['Chara','Lisette','Corine','Kevin','Carlee'];
while(nameArray.length > 0) { // while the array is not empty
let i = Math.floor(Math.random() * nameArray.length); // pick a random element index
console.log(nameArray[i]); // print the element
nameArray.splice(i, 1); // remove the element from the array
}
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 am trying to make a sorting visualizer. But when I am creating a array using following code, every time when I create a new array I am getting the same array as previous one! I have to refresh the page to get a new array. What will I have to do in order to get different array without refreshing through browser.
let sortingMethod = "";
let array = [];
function between(max) {
return Math.floor(Math.random() * Math.floor(max));
}
function createArray() {
for(let i = 0; i < 20; i++) {
array.push(between(20));
}
let arena = document.querySelector(".arena");
arena.innerHTML = '';
for(let i = 0; i < 20; i++) {
let element = document.createElement('div');
element.setAttribute('class', 'element');
console.log(array[i]);
element.style.height = (array[i] * 20) + "px";
arena.appendChild(element);
}
//console.log("created");
}
let create = document.getElementById("create");
create.addEventListener('click', createArray);
You are never clearing your array. So, each time you call createArray, new values are just appended to the end of the already filled array, but you only use first 20 values each time.
To solve your problem, just write this part of code let array = []; inside your createArray function.
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();
What is the best way in JavaScript given an array of ids:
var ids = ['ax6484', 'hx1789', 'qp0532'];
and a current id hx1789 to select another value at random that is not the current from the ids array?
Get the index of the value, generate a random value, if the random is the index, use 1 less (depending on random generated)
var random = Math.floor(Math.random() * ids.length)
var valueIndex = ids.indexOf("hx1789");
if (random === valueIndex) {
if (random === 0) {
random = 1;
} else {
random = random - 1;
}
}
var randomValue = ids[random];
Demo: http://jsfiddle.net/sxzayno7/
And yeah, test the array length, if it's 1 - probably don't want to do this! Thanks #ThomasStringer
if (ids.length > 1) { //do it! }
Or just filter out the value and pull against that:
var randomIndex = Math.floor(Math.random() * (ids.length - 1))
var random = ids.filter(function(id) {
return id !== "hx1789";
})[randomIndex]
I would probably do something along the lines of:
var current = 'hx1789'; // whatever variable stores your current element
var random = Math.floor(Math.random() * ids.length);
if(random === ids.indexOf(current)) {
random = (random + 1) % ids.length;
}
current = ids[random];
Basically if the newly picked element sits on the same index, you just pick the next element from the array, or if that goes out of bounds, pick the first.
UnderscoreJS is your best friend!
_.sample(_.without(['ax6484', 'hx1789', 'qp0532'], 'hx1789'));
or with variables;
var myArray = ['ax6484', 'hx1789', 'qp0532'];
var currentId = 'hx1789';
var newRandomId = _.sample(_.without(myArray , currentId));
You could make a duplicate array, then remove the current indexed element from that array and select an random element from the duplicate with the removed item:
var ids = ['ax6484', 'hx1789', 'qp0532'];
var currentIndex = ids.indexOf('hx1789');
var subA = ids.slice(0);
subA.splice(currentIndex , 1);
var randItem = subA[Math.floor((Math.random() * subA.length))];
Example Here.
This gets trickier if your value is not a simple string such as hx1789 but rather for instance comes from an array within the array you want to generate a different value from:
let weekSegments = [["Su","Mo"],["Tu","We"],["Th","Fr","Sa"]];
If you have the index it's simple, no matter how deeply nested the array (or object) is and/or the types of the values it contains:
let index = 1;
let segment = weekSegments[index];
let randomIndex;
let randomSegment;
if (weekSegments.length >= 1) {
randomIndex = Math.floor(Math.random) * (weekSegments.length - 1);
randomSegment = weekSegments.filter((val, i) => i !== index)[randomIndex];
}
Without the index though things get more complicated due to having to test for array and/or object equality in the filter function. In the case above it's fairly easy because it's an array that is only one-level deep which in turn only contains simple values. First we create a string representation of the sorted segment values we already have, then compare that to a string representation of val on each filter iteration:
let segmentVals = segment.sort().join(',');
if (weekSegments.length > 1) {
randomIndex = Math.floor(Math.random) * (weekSegments.length - 1);
randomSegment = weekSegments.filter((val) => {
return segmentVal !== val.sort().join(',');
})[randomIndex];
}
When dealing with objects rather than arrays and/or arrays/objects that are deeply nested and/or contain non-nested values it devolves into the sticky matter of object equality that is probably not entirely germane to this Q&A
I'm trying to manipulate an array inside a for loop, where I want to add an item to the end of the array and delete an element at the beginning of the array, like this:
var internal = new Array();
for(var i = 0; i < 1000; i++) {
internal[i] = Math.floor(Math.random() * 37);
internal.shift();
console.log(internal.length);
}
The problem is that it looks like shift() doesn't work inside the loop, in fact, no element is deleted from the array!
Is there a solution?
Here JsFiddle
It reduces by one every time, but you are growing it every time by accessing it with the array index accessing. Instead of
internal[i] = Math.floor(Math.random() * 37);
use
internal.push(Math.floor(Math.random() * 37));
For example,
var internal = [];
internal[3] = "thefourtheye";
console.log(internal);
Output
[ , , , 'thefourtheye' ]
It made space for the first three elements and added the element at the index specified. So, it will keep the array growing.
Note: Use [] to create a new array, instead of new Array()
because you are using a hard coded index, try
var internal = new Array();
for(var i = 0; i < 1000; i++) {
internal.push(Math.floor(Math.random() * 37));
internal.shift();
console.log(internal.length);
}
Demo: Fiddle
//test
var arr = [];
arr[50] = 1;
console.log('arr.length', arr.length);
will print 51 not 1