2

I have a string array with length is 100. I want to get random 8 elements among 100 element without duplicated elements in C#. Please help me. I appreciate it. I just use:

   for (int i = 0; i < 8; i++)
   {
        work with 8 values here
   }

Above code just performs to get 8 first values not 8 random values.

user3009966
  • 41
  • 1
  • 6

4 Answers4

6

Easy way:

var random = new Random();
var randomValues = arr.OrderBy(x => random.Next()).Take(8)

Effective way: use Fisher–Yates shuffle. Jon Skeet provided the implementation here.

Community
  • 1
  • 1
Andrzej Gis
  • 13,706
  • 14
  • 86
  • 130
  • This performs an awfully big sort to extract an awfully small number of values. – Rawling Jul 19 '15 at 18:19
  • 1
    @Rawling You're right. When performance matters Fisher-Yates shuffle algorithm should be considered (added reference to Jon Skeet's implementation) – Andrzej Gis Jul 19 '15 at 18:27
0

Here is the code. Explanation Randomly generate numbers between 0 - 99.

Using a hashset to keep track of indices that I am picking. If the index is present in hashset then it means that the value has already been selected, so skip it.

If the values in array are not unique, then in hashset instead of tracking index track values.

public List<string> GetRandomElements(string[] givenArray)
{
    if(givenArray == null || givenArray.Length == 0)
    {
        throw new ArgumentNullException("givenArray");
    }

    var rand = new Random();

    var randomArray = new List<string>();

    var indexTracker = new HashSet<int>();
    while(randomArray.Count < 8)
    {
        var nextIndex = rand.Next(0, givenArray.Length);

        if(indexTracker.Contains(nextIndex))
        {
            continue;
        }

        randomArray.Add(givenArray[nextIndex]);
        indexTracker.Add(nextIndex);
    }

    return randomArray;
}

Note I assumed here there was no constraint on using extra memory for hashset (because there will be max of 8 members only). If that is the constraint, then another way could be, split the index into 8 parts. So pick first index between 0-8, next index between 9-16 and so one. This way you will get unique numbers.

Monil Gandhi
  • 544
  • 1
  • 5
  • 13
0

It's pretty straightforward, just pass it to HashSet<string> and apply the following logic:

var mySet = new HashSet<string>(myList);
var myList = new List<string>();
var random = new Random();
for (int i = 0; i < 8; i++)
{
    int randValue = random.Next(0, mySet.Count());
    string randSetValue = mySet.ElementAt(randValue);
    myList.Add(randSetValue );
    mySet.Remove(randSetValue);
}
Orel Eraki
  • 11,940
  • 3
  • 28
  • 36
0

You can use generics and simply do:

    static T[] GetRandomRange<T>(T[] arr, int length)
    {
        var r = new Random();

        List<T> elementsList = new List<T>();

        for (; elementsList.Count < length; )
        {
            T el = arr[r.Next(0, arr.Length)];
            if (!elementsList.Contains(el)) elementsList.Add(el);
        }
        return elementsList.ToArray();
    }

Use it like :

int[] arr ... 
int[] newArray = GetRandomRange(arr, 8);

MyClass[] arr2...
MyClass[] newArray2 = GetRandomRange(arr2, 5);
Fabjan
  • 13,506
  • 4
  • 25
  • 52