Removing all items from an array (individually) - javascript

I have an array with a finite number of items in it. I want to randomly remove items until all the items have been used once.
Example [1,2,3,4,5]
Random number 5 is used, so I don't want that again.
Random number 2 is used, so I don't want that again.
And so on..
I could have another list of used numbers and check that the new random number is not in it, but that could take a long time when there is only 1 or two numbers left in the array out of 50.
Is there a way to remove an item from an array in javascript? Does it create a new array and would that be inefficient?
Are arrays the wrong way to do this?
EDIT: A few good answers here. I ended up randomizing the array list and then splicing the first item which is the one I took out.

Use the combination of Math.random() and splice():
var arr = [1, 2, 3, 4, 5],
i;
while ( arr.length ) {
i = Math.floor( Math.random() * arr.length );
alert( arr.splice(i, 1) );
}
Live demo: http://jsfiddle.net/simevidas/n2Bmk/
Update: You can use this function to remove a random item from your array:
function popRandomItem(arr) {
return arr.length ?
arr.splice(Math.floor(Math.random() * arr.length), 1)[0] : null;
}
So, if you have an array x, then popRandomItem(x) will remove a random item from that array and return that item. (If x is an empty array, the function will return null.)
Live demo: https://jsbin.com/wetumec/edit?js,console

You can use splice() to remove array elements.
Update
The function below lets you specify an upper and lower bound, and calling the resulting returned function will return a random number until the pool is empty, in which case it will return false (make sure you detect this with getRandom() === false).
var getRandomNumberOnce = function(lower, upper) {
var pool = [];
for (var i = lower; i <= upper; i++) {
pool.push(i);
}
return function() {
if (pool.length == 0) {
return false;
}
var randomIndex = Math.floor(Math.random() * pool.length ),
randomNumber = pool[randomIndex];
pool.splice(randomIndex, 1);
return randomNumber;
}
}
jsFiddle.
Usage
var myRandom = getRandomNumberOnce(0, 50);
myRandom(); // 4 (guaranteed to be random) :P http://xkcd.com/221/

I understand you're asking about removing elements but I'm going to go ahead and suggest an alternative way. This way does the same thing you want (getting a random element only once) but doesn't involve removing elements - well, it doesn't have to.
Essentially, randomise the order of your array rather than looking for random elements. Then work your way through the array for the random element you need. Your first random element will be at the 0 index, second random element will be at 1 index, etc.
var array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14];
array.sort(function(){ return (Math.round(Math.random())-0.5); });
for(var i=0;i<array.length;i++){
$("#list").append('<li>Random element ' + i + ': ' +array[i]);
}
Example: http://jsfiddle.net/jonathon/Re4HK/
Another question talks about randomising a JavaScript array but I just used a basic random sort as it works to illustrate the idea. You might want to look at that if you're concerned about how random your array is.

Sometimes you want a random item and don't
care if it is repeated once in a while.
Other times you want to quit when the aray is empty,
and see no repeats.
Array.prototype.getRandom= function(cut){
var i= Math.floor(Math.random()*this.length);
return cut? this.splice(i, 1): this[i];
}

Related

How do I efficiently check if an integer is not in a massive array in Javascript

I'm working on an assignment where I have to find the smallest positive integer greater than 0 that is NOT within a huge array including 100,000 elements. I'm able to do it so it's correct but apparently my solution takes way too long and returns a timeout error.
this is my current solution:
function solution(A) {
let min=1
while(A.includes(min) === true){
min++
}
return min
}
Is there a faster way of doing this that doesn't involve looping through every single element?
edit: whoops guys I forgot a key element to this question!
edit 2: the minimum value would be -2 and the maximum value would be 100,000 and they are not in order
You could take an object and add each wanted value to the object.
Then take the smallest key and check if is is equal to one and increment until no key is found. Otherwise return one.
function getSmallest(array) {
let temp = Object.create(null),
smallest;
for (const v of array) if (v > 0) temp[v] = true;
smallest = +Object.keys(temp)[0];
if (smallest !== 1) return 1;
while (temp[++smallest]);
return smallest;
}
console.log(getSmallest([2, 1, 0])); // 3
console.log(getSmallest([2, 3, 0])); // 1
I do believe this is a test to see if you know search algorithms for an unsorted array. Have you been taught about binary search?
I wrote code for following statement: "Find minimal positive integer NOT in array of numbers that could be any from -2 to 10000".
const arr = [5,4,6,7,5,6,4,5];
const p = new Array(10004);
arr.forEach(el => p[el + 2] = 1);
let answer = 10004;
for (let i = 3; i < 10004; ++i) {
if (!p[i]) {
answer = i - 2;
console.log(answer);
break;
} else if (i == 10003) {
console.log('no solution');
}
}
Sorting the array seems like a good place to start. Then you can loop or binary search from there to find your smallest positive integer.

Javascript: Unshift() is causing an infinite loop but can't see why

I am trying to make a function that takes an array and returns the array with the even numbers before the odd numbers. I figured I'd iterate through the array and check the divisibility of each number with modulo. If it's an even number, I unshift that number to the front of the array and keep going.
I've removed unshift to log that it iterates through so I know the issue isn't with my loop.
/// A = [3,5,6,3,4,2,1]
var sortArrayByParity = function(A) {
for (var x =0; x< A.length;x++) {
if (A[x] % 2 == 0) {
A.unshift(A[x])
}
}
return A;
};
Maximum stack error is occuring.
Because unshift adds an element to the array, thereby increasing its length. Furthermore, once the unshift adds an element to the beginning of the array, the next A[x] is the same as the previous one, as all elements get moved to the right, including x. So the loop never finishes, because the index x never reaches the ever increasing length.
If you need to add elements to an array through which you are iterating with a loop, it's better to do it with push in a loop that counts downwards from length to 0. That way, the loop will never iterate through added elements, and the elements that it will iterate through will not move.
When you unshift an array an element is added to the start of that array and increase the length.
Lets try
let arr = [1];
console.log('arr = ',arr, 'length =', arr.length);
arr.unshift(0);
console.log('arr = ',arr, 'length =', arr.length);
As a result when you find a even number you unshift it to the front but it will also be available in x + 1 position. and as you iterate you will find the same even number in next iteration.
correct implementation would be.
/// A = [3,5,6,3,4,2,1]
var sortArrayByParity = function(A) {
for (var x =0; x< A.length;x++) {
if (A[x] % 2 == 0) {
A.unshift(A[x]);
A.splice(x+1, 1);
}
}
return A;
};
console.log(sortArrayByParity([3,5,6,3,4,2,1]));
You should use both unshift and splice.

What's the fastest way to find the n smallest numbers in an array?

I have a list of numbers and I need to find the n smallest of them.
This is what I have so far, but I'm sure it must be possible to do it faster and cleaner (maybe without having to sort the entire list first?):
var list = [56,34,27,4,78,12,89,1002,45,33,87,90];
var results = [];
var sorted_list = list.slice(); // fastest way to duplicate array
sorted_list.sort(function (a, b) {
return a - b;
});
for (var i = 0; i < n; i++) {
// do stuff with sorted_list[i] and list
// push the result to results
}
return results;
I think if you use a Min Heap to solve this problem, it will be faster. By that I mean
Form a min heap from an array.
Take out the min element and heapify.(This step you will repeat, depending upon how many items you want)
Sorting algorithm will take O(N*logN) time, while Min Heap creation(step 1) will take O(N) time and O(logN){average} will be time taken by the second step.
Note that: Heap is useful when the number of items you needs is less than N. If you repeat the step 2 N times, the total time comes out to O(N*logN) itself same as sorting.
Array.min = function( array ){
return Math.min.apply( Math, array );
};
Source: http://ejohn.org/blog/fast-javascript-maxmin/
Thanks for the clarification. For n elements use:
Array.min = function( array, n ){
return array.sort(function(a, b){return a-b}).slice(0, n);
};
Without sorting it can be done in this way.
Basically the idea is that everytime in each iteration we will push the smallest number in an array.
and will remove that number from the main array
Suppose we have an array of length 12
a=[-11,2,1,5,0,9,-8,6,-10,0,12,4];
and we have to find 4 smallest number
we can find using this function(am is the result array)
function findmin(a) {
var item=Math.min.apply(Math, a);
var index= a.indexOf(item);
am.push(item);
a.splice(index, 1);
if(am.length<n)
findmin(a)
}
Now suppose we have to find 9 smallest number from the array
we can find(12-9=3) max number and remove it from the given array and then that will be our
result.
function findmax(a) {
var item=Math.max.apply(Math, a);
var index= a.indexOf(item);
am.push(item);
a.splice(index, 1);
if(a.length>n)
findmax(a)
}
Here I think the complexity is nm where m is no. of element to be found and n is total no. of element.If I am not wrong.
Actually i am weak in finding complexity.So please suggest if any improvement can be done.
SEE DEMO HERE

Javascript : Exclude an element from a random set - (curiosity)

I have a question regarding javascript Math.random():
I have (for a game I'm building) to randomly generate every number from a given set (i.e. from 0 to 1000) and every time I have to generate a number, I have to check if that number has already been "generated".
The solution is pretty easy thinking about a simple algorithm that checks if the random integer is already present in the generated set. It loops generating numbers until it can't find it.
A snippet below:
/* ... */
for(var i = 0; i<upperBound; i++){
var randN = Math.floor(Math.random()*upperBound);
while(myRandomNumbers.contains(randN)){
loops++;
randN = Math.floor(Math.random()*upperBound);
}
myRandomNumbers.push(randN);
}
/* ... */
running example here
I'd like to know: is this the best way to achieve this? or are there any ways, instead of looping until it generates a "good" number, to exclude a particular set in the random generation?
Thanks a lot everyone!
Generate the set of numbers in order.
Sort the list randomly.
Here's an example using a naive, biased sort:
for (var nums=[],i=0;i<1000;++i) nums[i]=i+1;
nums.sort(function(){ return Math.random()-0.5 });
Then you can just pop() numbers off of nums to get the next 'random' number, guaranteed to never have been used before.
If your range of number is not prohibitively large, you could simply generate a list with all the numbers, randomise it, then pick it off one by one.
Here's a quick hack of your sample implementation to show this method in action: http://www.jsfiddle.net/ZTLt9/8/
I'd create an array and randomly shuffle it:
function shuffle(arr) {
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--) {
index = Math.floor(i * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled;
}
// Create the array
var i = 1000, arr = [];
while (i--) arr[i] = i;
// Shuffle it
arr = shuffle(arr);
What about an array of booleans 1001 big.
When you want to check of the number has been generated, all you need to do is check the number at that position in the array:
if (!arr[randomnumber]){
arr[randomnumber] = true;
}
At the end, you can scan the array to find the numbers you need.
This has the added side effect of sorting your numbers, as the scan will pick them out in order.
Something similar to this was the subject of one of my blog posts:
http://www.jameswiseman.com/blog/2010/05/27/generate-and-sort-lottery-numbers/
The best way would probably be to generate an array of numbers, then shuffle it using the Fisher-Yates shuffle.
Here is the JavaScript example given in the Wikipedia article:
var n = a.length;
for(var i = n - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
(This assumes you have an array 'a' that contains the items you wish to shuffle.)

How would you keep a Math.random() in javascript from picking the same numbers multiple times?

I have an array var words = []//lots of different words in it. I have a Math.floor(Math.random()*words.length) that chooses a random word from the array. This is run in a loop that runs for a random number of times (between 2 and 200 times). I would like to make sure that the random numbers do not get chosen more than once during the time that that loop runs. How would you suggest doing this?
There's multiple ways of doing this.
You can shuffle the entire collection, and just grab items from one end. This will ensure you won't encounter any one item more than once (or rather, more than the number of times it occured in the original input array) during one whole iteration.
This, however, requires you to either modify in-place the original collection, or to create a copy of it.
If you only intend to grab a few items, there might be a different way.
You can use a hash table or other type of dictionary, and just do a check if the item you picked at random in the original collection already exists in the dictionary. If it doesn't, add it to the dictionary and use it. If it already exists in the dictionary, pick again.
This approach uses storage proportional to the number of items you need to pick.
Also note that this second approach is a bit bad performance-wise when you get to the few last items in the list, as you can risk hunting for the items you still haven't picked for quite a number of iterations, so this is only a viable solution if the items you need to randomly pick are far fewer than the number of items in the collection.
There are several different approaches, which are more or less effective depending on how much data you have, and how many items you want to pick:
Remove items from the array once they have been picked.
Shuffle the array and get the first items.
Keep a list of picked items and compare against new picks.
Loop through the items and pick values randomly based on the probability to be picked.
I'd shuffle the array as follows and then iterate over the shuffled array. There's no expensive array splice calls and the shuffling routine consists of swapping two values in the array n times where n is the length of the array, so it should scale well:
function shuffle(arr) {
var shuffled = arr.slice(0), i = arr.length, temp, index;
while (i--) {
index = Math.floor(i * Math.random());
temp = shuffled[index];
shuffled[index] = shuffled[i];
shuffled[i] = temp;
}
return shuffled;
}
console.log(shuffle(["one", "two", "three", "four"]));
this is how you can do it without shuffling the whole array
a = "abcdefghijklmnopq".split("");
c = 0;
r = [];
do {
var len = a.length - c;
var rnd = Math.floor(Math.random() * len);
r.push(a[rnd]);
a[rnd] = a[len - 1];
} while(++c < 5);
console.log(r);
the idea is to pick from 0..(length - step) elements and then shift the picked element towards the end.
I'd try using a map (Object literal) instead of an Array with keys being indexes:
var words = [ /* ... */ ] , map = { } , length = words.length ;
for(var n = 0 ; n < length ; n++) map[n] = words[n] ;
then make a function to pick a random entry based on the length, delete the entry (hence the index) and adjust the length:
function pickRandomEntry() {
var random = Math.floor( Math.random() * length ) ;
var entry = map[random] ;
delete map[random] ;
length-- ;
return entry ;
}
with this approach, you have to check for an undefined return value (since random might return the same number) and run the function again until it returns an actual value; or, make an array of picked indexes to filter the random numbers (which will however slow performance in case of long iteration cycles).
HTH
There are several solutions to this.
What you could do is use .splice() on your array to remove the item which is hit by words.
Then you can iterate over your array until it's empty. If you need to keep the array pristine you can create a copy of it first and iterate over the copy.
var words = ['apple', 'banana', 'cocoa', 'dade', 'elephant'];
while (words.length > 0) {
var i = Math.floor(Math.random()*words.length);
var word = words.splice(i, 1)[0];
}
Or something to that effect.
Here is a way with prime numbers and modulo that seems to do the trick without moving the original array or adding a hash:
<html>
<head>
</head>
<body>
shuffle
<div id="res"></div>
<script>
function shuffle(words){
var l = words.length,i = 1,primes = [43,47,53,59,61,67,71,73,79],//add more if needed
prime = primes[parseInt(Math.random()*primes.length, 10)],
temp = [];
do{
temp.push((i * prime) % l);
}while(++i <= l);
console.log(temp.join(','));
console.log(temp.sort().join(','));
}
</script>
</body>
</html>

Categories

Resources