1

What is the best way to randomize items in an array and also remove random items to get to a required array length?

Let's say I have an array with 100 items.

First, I want to randomize it.

Then, I have three percent coefficients: 10%, 30%, 60%.

I want to remove items from the original array so the new array I get will be 60% of the original size (60 items), then 30%, then 10%.

Richard Knop
  • 81,041
  • 149
  • 392
  • 552

2 Answers2

5

The best way to randomise the array would be to use a Fisher-Yates-Durstenfeld shuffle. You could either do this in-place (ie, shuffle the existing array) or create a new collection containing the items in random order.

Here's how I'd probably do it, creating a new shuffled collection rather than mutating the original array, and then using Skip and Take to get the required sub-sequences of the shuffled array. (And it would be easy enough to alter this code to perform an in-place shuffle instead, if you prefer.)

// uses Shuffle extension from https://stackoverflow.com/a/1653204/55847
var temp = original.Shuffle().ToArray();
var sixty = temp.Take((int)(temp.Length * 0.6)).ToArray();
var thirty = temp.Skip(sixty.Length).Take((int)(temp.Length * 0.3)).ToArray();
var ten = temp.Skip(sixty.Length + thirty.Length).ToArray();
Community
  • 1
  • 1
LukeH
  • 263,068
  • 57
  • 365
  • 409
2

Well, first of all you can't remove items from an array. The size of an array is determined when it's created, and can never change after that. If you want a smaller array, you have to create a new one.

You can shuffle the items using an extension like this:

public static class IEnumerableExtensions {

  public static IEnumerable<T> Shuffle<T>(this IEnumerable<T> list, Random rnd) {
    List<T> items = new List<T>(list);
    for (int i = 0; i < items.Count; i++) {
      int pos = rnd.Next(i, items.Count);
      yield return items[pos];
      items[pos] = items[i];
    }
  }

}

I'm not exactly sure what you mean by the coefficients, but I guess that you want to get the first 60% in one array, then another 30% in second array, then another 10% in a third array:

IEnumerable<int> shuffled = originalArray.Shuffle(new Random()).ToList();

int cnt60 = (int)Math.Round(originalArray.Length * 0.6);
int cnt30 = (int)Math.Round(originalArray.Length * 0.3);
int cnt10 = (int)Math.Round(originalArray.Length * 0.1);

int[] first60 = shuffled.Take(cnt60).ToArray();
int[] next30 = shuffled.Skip(cnt60).Take(cnt30).ToArray();
int[] next10 = shuffled.Skip(cnt60+cnt30).Take(cnt10).ToArray();
Guffa
  • 687,336
  • 108
  • 737
  • 1,005