Skip to main content
added 71 characters in body
Source Link
DMGregory
  • 141k
  • 23
  • 258
  • 401

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method will take on average 3-4 times longer in this scenario, because its probability of choosing a duplicate and retrying goes up the longer our output list gets in proportion to the input. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, since the list only contains 2 valid non-duplicate choices out of 50. The linear scan guarantees that we pick each item in a single try while avoiding duplicates through the re-ordering trick.

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method will take on average 3-4 times longer, because its probability of choosing a duplicate and retrying goes up the longer our output list gets in proportion to the input. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, since the list only contains 2 valid non-duplicate choices out of 50. The linear scan guarantees that we pick each item in a single try.

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method will take on average 3-4 times longer in this scenario, because its probability of choosing a duplicate and retrying goes up the longer our output list gets in proportion to the input. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, since the list only contains 2 valid non-duplicate choices out of 50. The linear scan guarantees that we pick each item in a single try while avoiding duplicates through the re-ordering trick.

Specifics
Source Link
DMGregory
  • 141k
  • 23
  • 258
  • 401

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method canwill take muchon average 3-4 times longer, because its probability of choosing a duplicate and retrying goes up the longer our output list gets in proportion to the input. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, whilesince the list only contains 2 valid non-duplicate choices out of 50. The linear scan picksguarantees that we pick each item in a single try.

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method can take much longer, because its probability of choosing a duplicate goes up the longer our output list gets. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, while the linear scan picks each item in a single try.

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method will take on average 3-4 times longer, because its probability of choosing a duplicate and retrying goes up the longer our output list gets in proportion to the input. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, since the list only contains 2 valid non-duplicate choices out of 50. The linear scan guarantees that we pick each item in a single try.

Source Link
DMGregory
  • 141k
  • 23
  • 258
  • 401

You can do this faster than a Hashset with a simple linear scan:

var randomObjects = new GameObject[waypointsCount]; 

for(i = 0; i < waypointsCount; i++) {
    // Take only from the latter part of the list - ignore the first i items.
    int take = Random.Range(i, Nodes.Length);
    randomObjects[i] = Nodes[take];

    // Swap our random choice to the beginning of the array,
    // so we don't choose it again on subsequent iterations.
    Nodes[take] = Nodes[i];
    Nodes[i] = randomObjects[i];
}

This is effectively a Fisher-Yates shuffle (also called a Knuth shuffle) that terminates early.

Doing it this way has a couple of advantages:

  • we can build the output array in-place (even just using the same memory as the input Nodes array if we want to), without setting aside extra memory for the hash structure for membership tests.

  • if we want 49 items from a list of 50, we finish in exactly 49 iterations, every time. The Hashset method can take much longer, because its probability of choosing a duplicate goes up the longer our output list gets. To pick the last random item in this scenario, the Hashset would need to try 25 times on average, while the linear scan picks each item in a single try.