0

In my code below, an object from my array is taken randomly. What I want however that there is always a defined ratio of how the objects are taken.

The ratio here is 1 ANIMAL, 1 LETTER, 4 INTEGERs, and I run the random selection in an interval 24 times and want the ratio to remain exactly the same: 4 ANIMALs, 4 LETTERs, 16 INTEGERs. As it is now, it will not do so and probably only approximate the true ratio for an infinite number of 'runs'.

var teststim =  [
        {stim: "CAT",   type: "ANIMAL"},
        {stim: "A",     type: "LETTER"},
        {stim: "3",     type: "INTEGER"},
        {stim: "7",     type: "INTEGER"},
        {stim: "5", type: "INTEGER"},
                {stim: "9", type: "INTEGER"}]
newthing = teststim[Math.floor((Math.random() * teststim.length))];

How would I do that, is there a way to define the exact ratio of such a semi-random randomisation?

ben_aaron
  • 1,504
  • 2
  • 19
  • 39
  • The ratio for your one execution is only *approximately* 1/6 : 1/6 : 2/3 as well. – Bergi May 14 '14 at 09:58
  • @Bergi: I think the execution is there as an example of how OP now gets the data. If he wants 24 items, he'll presumably be calling that 24 times. (OP can confirm?) – Flater May 14 '14 at 10:01
  • From the 16 integers, do you want 4 times `3`, 4 times `5` etc, or do you just want 16 random integers? – Bergi May 14 '14 at 10:02
  • @Bergi Just 16 random integers would do. – ben_aaron May 14 '14 at 11:01

2 Answers2

1

Think of your ratio as a separate action. Every time you take something from the list, you actually take 1 animal, 1 letter, and 4 integers (each randomly)

If you think of taking that ratio as a single action, all that remains is calling that single action multiple times:

I don't know if the amount of items you take in total should be random, so I'm assuming you want 24 items total:

for(var i = 0; i < 4; i++) //4 iterations * 6 random items per action = 24 total
{
    TakeRandomRatioFromList(sourceList, targetList);
}

....

function TakeRandomRatioFromList(sourceList, targetList)
{
    //Take 1 random ANIMAL for sourceList, add it to targetList

    //Take 1 random LETTER for sourceList, add it to targetList

    //Take 4 random INTEGERS for sourceList, add it to targetList    
}    

This way, you can ensure that the taking of a number will ALWAYS be run 4 times for each animal and letter that was taken. All you have to do is make sure you only get items from the sourceList by using that function.

Flater
  • 12,908
  • 4
  • 39
  • 62
  • I'll give that a try, thanks. My sourceList being the array of objects where I take randomly animal, letter, integers based on the 'type' attribute? And further usage then exclusively from my targetList? Or am I wrong? – ben_aaron May 14 '14 at 11:05
  • sourcelist is the original list you mentioned in your snippet. target list is the list of picked items. I'm not too knowledgeable about Jsson and how to define your random selection, but a working (but unoptimized) solution is `do{ pickedItem = sourceList[Math.floor((Math.random() * teststim.length))]; }while (pickedItem.Type !== "ANIMAL")`. Once you've passed the while loop, just add that item to your targetList. There are probably better ways though. – Flater May 14 '14 at 11:09
1

Usually you would use a shuffle, if you want a defined set of items in a random order. In your case, you will also need to pick random items for each type, though:

var items = [
   [ {stim: "CAT", type: "ANIMAL"}],
   [ {stim: "A", type: "LETTER"}],
   [ {stim: "3", type: "INTEGER"},
     {stim: "7", type: "INTEGER"},
     {stim: "5", type: "INTEGER"},
     {stim: "9", type: "INTEGER"}],
];
var times = 4;

var result = [];
for (var i=0; i<times; i++)
    for (var j=0; j<items.length; j++) {
        var choose = items[i],
            cholen = choose.length;
        for (var k=0; k<cholen; i++)
            result.push(choose[Math.floor(Math.random()*cholen)]);
    }
// now we have 4 "random" cats, 4 "random" letters, and 16 random integers

result.shuffle();

Then, shuffle the array with your favorite algorithm, e.g. the Fisher-Yates-Knuth shuffle (see there for Array.prototype.shuffle as used above).

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375