I've been working on a project recently where I had the need to randomly shuffle all of the rows in a DataTable. I wanted to do it with the DataTable itself instead of in the act of populating the DataTable for a couple of reasons: 1) I wanted to keep the DataTable in memory and shuffle it in place multiple times without going back to the source, and 2) I had multiple sources where data was coming from (SQL and XML) so I preferred to keep the randomization logic in one place. I also didn't want to copy all of the data (even though it was not a large amount) each time I shuffled, so I decided to use a DataView to display the data shuffled each time I needed it.
Here's the utility function I came up with - each time you call RandomizeDataTable it will return a newly shuffled DataView of all the data passed in through the DataTable. Note that because I reuse the added column "rndSortId" each time, any DataViews retrieved from previous calls to the method will have the new shuffle order. You could change this behavior by adding a new column each time with its own unique sort sequence.
As always, comments/improvements welcome – enjoy!
public static
class
DataSetUtilities
{
static
Random _rand = new
Random();
public
static
DataView RandomizeDataTable(DataTable dt)
{
// Create array of indices and populate with ordinal values
int[] indices = new
int[dt.Rows.Count];
for (int i = 0; i < indices.Length; i++)
indices[i] = i;
// Knuth-Fisher-Yates shuffle indices randomly
for (int i = indices.Length - 1; i > 0; i--)
{
int n = _rand.Next(i + 1);
int tmp = indices[i];
indices[i] = indices[n];
indices[n] = tmp;
}
// Add new column to data table (if it's not there already)
// to store shuffle index
if (dt.Columns["rndSortId"] == null)
dt.Columns.Add(new
DataColumn("rndSortId", typeof(int)));
int rndSortColIdx = dt.Columns["rndSortId"].Ordinal;
for (int i = 0; i < dt.Rows.Count; i++)
dt.Rows[i][rndSortColIdx] = indices[i];
DataView dv = new
DataView(dt);
dv.Sort = "rndSortId";
return dv;
}
}
For the attendees of tonight's user group talk in Waltham, you can grab the demos
here. Thanks for coming, and for all the great questions!
I'll be speaking next Wednesday (April 9, 2008) at the
Boston .NET User Group meeting in Waltham, MA. I'm going to look at the new control architecture in Silverlight 2 and talk about building reusable components in Silverlight, so if you're in the area, be sure to reserve the night - should be fun!
Here's a quick way to print the current row number in a Repeater control (I promised a conference talk attendee to post this recently):
<asp:Repeater ID="rep1" runat="server' DataSourceID="myds">
<ItemTemplate>
<%#(((RepeaterItem)Container).ItemIndex+1).ToString() %>
<-- other data binding expressions here... -->
</ItemTemplate>
</asp:Repeater>
If you attended my talk today on New Features of ASP.NET 3.5 and Visual Studio 2008 at DevWeek 2008, you can grab the demos
here.
Thanks for coming!
If you were at the user group meeting in London tonight for VBUG,
here are the demos for the talk. Thanks for coming and for all the great questions!
If you attended my talk (or talks) today on Silverlight ASP.NET Controls and Silverlight Server Communication at DevWeek 2008, you can grab the demos
here and
here respectively.
Thanks for coming!
If you attended my talk today on ASP.NET Ajax Design at DevWeek 2008, you can grab the demos
here. Thanks for coming!
Thanks to all who attended today's pre-conference tutorial on Silverlight with myself and Ian Griffiths. You can grab the demos
here.
Remember to stop by the Pluralsight booth if you were one of the t-shirt winners to collect your prize (and please stop by even if you weren't)!
While I'm in London at
DevWeek, I will also be presenting at
VBUG on March 12 on building user controls in Silverlight 2.0. Hope to see you there!