4

I have a collection contains let say 100 items.

Collection<int> myCollection = new Collection<int>();

for(int i; i <= 100; i++)
{
    myCollection .Add(i);
}

How can i randomly select items by percentage(eg. 30%) from this collection?

My2ndLovE
  • 397
  • 4
  • 18

2 Answers2

4

Try this:

var rand = new Random();
var top30percent = myCollection.OrderBy(x=> rand.Next(myCollection.Count))
                               .Take((int)(0.3f*myCollection.Count)).ToList();

You can remove the ToList() if you want some deferred query.

King King
  • 61,710
  • 16
  • 105
  • 130
  • Only problem with this though is that its possible that the same item could be selected more than once. Which may or may not be okay, depending on the OPs needs – Icemanind Nov 23 '13 at 04:48
  • Nice! Yes, I need avoid the same item being selected more than once. – My2ndLovE Nov 23 '13 at 05:27
2

There's two parts in your question. First, you must shuffle your collection in order to select items randomly. To shuffle it, you can do it properly with the Fisher-Yates shuffle, or just order your items using a pseudo-random generator.

The Fisher-Yates shuffle comes from this popular answer :

public static IList<T> Shuffle<T>(this IList<T> list)  
{  
    Random rng = new Random();  
    int n = list.Count;  
    while (n > 1) {  
        n--;  
        int k = rng.Next(n + 1);  
        T value = list[k];  
        list[k] = list[n];  
        list[n] = value;  
    }  

    return list;
}

However, I'm returning the list so we can use it cleanly with the take part. Also, if you don't really need to shuffle cleanly, you can use a simple OrderBy with either i => random.Next() or i => Guid.NewGuid() as the lambda expression.

Secondly, once it's shuffled, now you need to take a percentage of items. You can do this simply by using the Take LINQ method.

Like the Shuffle method, you can make it as an Extension method :

public static IEnumerable<int> TakePercentage(this IList<int> list, int percentage)
{
    return list.Take(percentage * list.Count / 100);
} 

If you prefer receiving a decimal (e.g. 0.3) directly :

public static IEnumerable<int> TakePercentage(this IList<int> list, double percentage)
{
    return list.Take((int)(percentage * list.Count));
} 

Finally, to use it, it's quite simple :

var thirtyPercent = myCollection.Shuffle().Take(30);
Community
  • 1
  • 1
Pierre-Luc Pineault
  • 8,993
  • 6
  • 40
  • 55