My2ndLovE
My2ndLovE

Reputation: 397

Select items from ASP.NET collections by percentage

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?

Upvotes: 4

Views: 360

Answers (2)

Pierre-Luc Pineault
Pierre-Luc Pineault

Reputation: 9201

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);

Upvotes: 2

King King
King King

Reputation: 63367

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.

Upvotes: 4

Related Questions