Click here to Skip to main content
Licence CPOL
First Posted 28 Apr 2009
Views 8,863
Downloads 31
Bookmarked 7 times

Adding Random Functionality to Generic Lists using Extension Methods

By andywilsonuk | 29 Apr 2009
Extends IList to include a shuffle method and a 'select an element at random' method.

1

2
2 votes, 66.7%
3

4
1 vote, 33.3%
5
3.40/5 - 3 votes
μ 3.40, σa 2.02 [?]

Introduction

The .NET Framework provides a vast array of functionality for manipulating lists. However one of the requirements that frequently crops up is having the ability to reorder a list into a random sequence or select a random element from a list. Both are relatively straightforward and can be achieved effectively with a couple of extension methods on IList<T> meaning they'll be available for use on any List<T> or ObservableCollection<T> as well as any classes that derive from them.

Note: This article has been updated, scroll to the bottom to see the history.

Selecting a Random Element

A method to select an element at random can be implemented using an extension method but must be on a static class.

Things to note are that Random.Next returns a value between 0 and list.Count – 1, i.e. less than the maximum specified (separately, I actually have an extension method for Random that can return a value using inclusive parameter values). The statement default(T) is used because value types cannot be set to null (think int as opposed to int?).

private static Random random = new Random();
 
public static T GetRandom<T>(this IList<T> list)
{
  if (list.Count == 0)
  {
    return default(T);
  }
  return list[random.Next(0, list.Count)];
}

Reordering a List

Now we have a flavour for Random how about manipulating the elements within a list. Again an extension method provides a neat way to do this:

public static void Shuffle <T>(this IList <T> list) 
{ 
  if (list.Count <= 1) 
  { 
    return; // nothing to do 
  } 
  
  for (int i = 0; i < list.Count; i++) 
  { 
    int newIndex = random.Next(0, list.Count); 
    
    // swap the two elements over 
    T x = list[i]; 
    list[i] = list[newIndex]; 
    list[newIndex] = x; 
  }
}

This works by looping over each element in the list and swapping it with another element at a randomly selected position. Note that like many things, this code will work fine when lists are reasonably small but it is outside the scope of this article to discuss optimisations for manipulating lists.

Conclusion

These methods are just two examples of how lists can be extended to include functionality that produces randomised output and by putting them onto a base generic interface that allows for reuse over a great many classes.

History

  • Version 1.0
    • Initial release
  • Version 1.1
    • Updated shuffle algorithm to be properly random
    • Improved sample

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

andywilsonuk

Software Developer (Senior)
Play.com
United Kingdom United Kingdom

Member
Hi, my name's Andy Wilson and I live in Cambridge, UK where I work as a Senior C# Software Developer.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
Generalincorrect shuffle and solution PinmemberJean-Paul Mikkers0:46 30 Apr '09  
GeneralMinor flaw PinmemberJoe Enos7:41 28 Apr '09  
Using this technique, the first element of the List will always be swapped once and only once, which means the first element of the new randomized List will never be the first element of the original List. For it to truly be random, that will need to be a possibility.
 
I'm no statistics expert, but I'd also guess that since the lower-ranked elements are swapped less often than the higher ones, that there would be not as equal a chance of each element being placed in a different location as other elements. But I'm not sure about that one.
 
Can I suggest an alternative? If you truly need random, how about a container that contains the T as well as a double, then populate a list of containers with the list of Ts and random doubles from 0 to 1, then sort the containers by the double, then extract the Ts. Probably not as good a performance, but I'd bet it's more truly random.
 
But I do like the concept - a Shuffle method would be useful.
 
Joe Enos
joe@jtenos.com

GeneralRe: Minor flaw Pinmemberdevwilson23:54 28 Apr '09  
GeneralRe: Minor flaw PinmemberIzzet Kerem Kusmezer2:00 5 May '09  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120210.1 | Last Updated 29 Apr 2009
Article Copyright 2009 by andywilsonuk
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid