1

i'm builing an hybrid app in Javascript that casually pick an exercise from a database, wait for the user to solve it and then pick another exercise.

Nothing difficult at this point, my problem is about picking always a different exercise from database.

Now my code 'works' in this way:

  1. Gets total number of exercises (about 3K),
  2. Generate a N random number from 1 to 3000,
  3. Pick the N exercise from DB,
  4. Save the N number in the 'used' db table,
  5. Generate another number name,
  6. This time first of all check if the generated number was already used,
  7. If NO pick exercise, if YES generate another number,
  8. etc...

The code works well for the first 2000-2500 numbers, then start to be really slow because generating a random number not already used starts to be very difficult. When the number used are just a bit less than 3K the code is totally broken: continues to check but the new number never comes

How can i handle this situation in a fast and light way that use memory as less as possible?

Thank you very much!

EDIT

I'm using WebSQL in a phonegap application

That's what i'm doing (code):

Here i get the number of the exercises

1. SELECT COUNT(*) AS countArt FROM Exercises'

Here i pick a random number from 1 to totalNumberOfExercises

2. randomNumber = random(totalNumberOfExercises);
   function numeroCasuale(len){
        var num = Math.floor(Math.random() * len) + 0;
        return num;
    };

Here i check if my randomNumber is already in the DB, that means is already used

4. SELECT EXISTS(SELECT * FROM alreadyUsed WHERE numero=randomNumber)

If randomNumber exists i generate another randomNumber and check it again and again...

Dawson Loudon
  • 6,029
  • 2
  • 27
  • 31
elledienne
  • 1,135
  • 1
  • 11
  • 18
  • 1
    Its better to generate an array out of all possible 3000 numbers, then delete the already used ones, and then get a random number from the remaining unused numbers – juvian Nov 26 '14 at 19:08
  • 1
    Put the numbers from 1 to 3000 into an array, then shuffle the array. Then you can just pick numbers by increasing an index into the array, and you're guaranteed not to get a duplicate. – Pointy Nov 26 '14 at 19:09
  • How are you generating this random number (SQL or application)? What database are you using? Can you post some code? – Pedro Moreira Nov 26 '14 at 19:12
  • @Pointy how do you shuffle the array? – frank Nov 26 '14 at 19:25
  • Generate a random number between 1 to 3000. If the number has `not been previously` generated, mark that number has used. If the number was `used previously`, use the `next` number i.e ( random number + 1). If it is the last number in the index, go to the first number. In this way you will always arrive at a `unused` number. In order to **speed up** the process, you could **pre-calculate** the random numbers and store in table and simply fetch the next index in the table one after another. – frank Nov 26 '14 at 19:32
  • The way you are doing it, think of the probability of a number from 1-3k falling in an ever shrinking set of usable values. @Pointy, that's a very stable solution! +1 – Dinesh Nov 26 '14 at 19:35
  • I've updated question with code! – elledienne Nov 26 '14 at 20:03

1 Answers1

2

Using this shuffle function from another stackoverflow question:

function shuffle(o){
    for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
    return o;
}

You can create this:

function generateRandomSequence(amount){
    var random = [];
    for (var i = 0; i<amount; i++) random[i] = i;
    return shuffle(random);
}

var random = generateRandomSequence(3000);
var gamesCompleted = 0;

function nextGame(){
    console.log(random[gamesCompleted]);
    gamesCompleted++;
}

nextGame();

This creates an array where position 0 = 0, 1 = 1 and so on and shuffle it so we have a random sequence without doublicates. Keep track of how many games you have completed and use this number as the index for the next question. Here's a fiddle.

Community
  • 1
  • 1
ostrgard
  • 380
  • 3
  • 9
  • i think your answer is good, but my problem is that i need to permanently store the array of random numbers because the code needs to work inside a peonegap app and i want the picked exercise to be unique even if the user close the app – elledienne Nov 26 '14 at 20:11
  • Aha. Well in that case, save it in local storage. Quick example, when the app starts check if `localStorage.getItem('randomSequence') == null` if true, generate the sequence and save it to localStorage, if false, get the item from there. You will need to use `JSON.stringify()` and `JSON.parse()`to store it as a string in localStorage. Don't forget to save and load the gamesCompleted amount it as well. Does that make sense? I can write up an example if you wish and add it to the answer. – ostrgard Nov 26 '14 at 22:23
  • Thank you very much! I know localStorage, I've just a question: isn't localStorage read/write quite "slow"? – elledienne Nov 26 '14 at 22:29
  • It can be if you have a lot of data, and also note it's synchronous, which means your app will hang while the data is loading. I think you should test it out to see the impact. Save a date object to a variable and subtract it from another date object after loading and saving. Bottom line, you'll be writing the sequence once per install lifetime, and retrieving it every time a user opens the app (not from background). It's not bad in my opinion. – ostrgard Nov 26 '14 at 22:37
  • What about using WebSQL (that i'm already using)? Should be faster, or am i wrong? – elledienne Nov 26 '14 at 22:39
  • I don't have experience with WebSQL, but if you're already using it, by all means keep doing that. Consistency is underated :) – ostrgard Nov 26 '14 at 22:40
  • Well, i will try to implement it! Thank you very much for your help! I will wait some days to see if there are others options and then i will accept the answer:) – elledienne Nov 26 '14 at 22:51
  • Thanks! I'm using your code and it's working very well!! – elledienne Nov 28 '14 at 10:58