1

I have an array (say 'origA') which contains 20 values and also another array (say "itemA" with only 1 value in it. I need to push any 10 random values of "origA" into "itemA". But i cannot push a same value which is already pushed into "itemA".

How can we do this?

3 Answers 3

3

You can create a copy of origA and remove from it the items you add to itemA:

Non optimized version:

var origA:Array = [1, 2, 3, 4, 5, 6, 7];
var itemA:Array = [0];

var copyA:Array = origA.concat();
var N:int = 10;
var n:int = Math.min(N, copyA.length);

for (var i:int = 0; i < n; i++) {
    // Get random value
    var index:int = Math.floor(Math.random() * copyA.length);
    var value:int = copyA[index];
    // Remove the selected value from copyA
    copyA.splice(index, 1);
    // Add the selected value to itemA
    itemA.push(value);
}

trace(itemA);
//0,1,7,2,6,4,3,5

Optimized version (no calls to length, indexOf, splice or push inside the loop):

var origA:Array = [1, 2, 3, 4, 5, 6, 7];
var itemA:Array = [0];

var copyA:Array = origA.concat();
var copyALength:int = copyA.length;
var itemALength:int = itemA.length;
var N:int = 10;
var n:int = Math.min(N, copyALength);
for (var i:int = 0; i < n; i++) {
    // Get random value
    var index:int = Math.floor(Math.random() * copyALength);
    var value:int = copyA[index];
    // Remove the selected value from copyA
    copyA[index] = copyA[--copyALength];
    // Add the selected value to itemA
    itemA[itemALength++] = value;
}

trace(itemA);
//0,2,5,7,4,1,3,6

Edit1: If your original array has only a few items, use my first version or any other solution in the other answers. But if it may have thousands items or more, then I recommend you use my optimized version.


Edit:2 Here is the time taken to copy 1,000 randomly chosen items from an array containing 1,000,000 items:

  • All other versions: 2000ms
  • Optimized version: 12ms
  • Optimized version without cloning the original array: 1ms
Sign up to request clarification or add additional context in comments.

4 Comments

Nice, though I figure working with an array of length 10 or even under 100 doesn't really need a solution that works without indexOf(), though I admit it's good for people looking for a similar solution with much larger arrays :)
I used a copy of the original array mainly to avoid altering it (using splice()) and not to avoid the use of indexOf(). It's only in the second optimized version that I avoid calling costly methods: length, indexOf, splice and push.
I have to agree on the indexOf() part - it will iterate from index 0 until it finds the item, which can be quite costly with a larger array.
@sch I can confirm your benchmarks. That's pretty impressive. I can also say that it's the call to splice() that made my solution slow. I will from now on adopt your way of removing values - thank you for the inspiration!
2
// Define how many random numbers are required.
const REQUIRED:int = 10;

// Loop until either the original array runs out of numbers,
// or the destination array reaches the required length.
while(origA.length > 0 && itemA.length < REQUIRED)
{
    // Decide on a random index and pull the value from there.
    var i:int = Math.random() * origA.length;
    var r:Number = origA[i];

    // Add the value to the destination array if it does not exist yet.
    if(itemA.indexOf(r) == -1)
    {
        itemA.push(r);
    }

    // Remove the value we looked at this iteration.
    origA.splice(i, 1);
}

3 Comments

I am sorry if i wasn't clear but I need any 10 random values without repetitions, not all.
@Marty Wallace all the values are different in the "origA" this problem should not occur. anyways, when i said without repetitions I meant if one random value is pushed into "itemA" from "origA" the same value should not be pushed again. You understand what i mean?
@weltraumpirat Math.random() never hands out 1 so assigning to int like I have always returns a value up to the length - 1...
2

Here's a real short one. Remove random items from the original array until you reach MAX, then concat to the target Array:

const MAX:int = 10;
var orig:Array = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
var target:Array = [];
var tmp:Array = [];
var i : int = -1;
var len : int = orig.length;
while (++i < MAX && len > 0) {
    var index:int = int( Math.random()*len );
    tmp[i] = orig[index];
    orig[index] = orig[--len];
}
target = target.concat(tmp);

EDIT

Adopted @sch's way of removing items. It's his answer that should be accepted. I just kept this one for the while-loop.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.