0

I need to shuffle rows of DataTable as randomly accessing indexes would not work in my scenario. So I have dt1 having base data which I have to shuffle and dt is the DataTable having shuffled data. And my code is:

int j;
for (int i = 0; i < dt1.Rows.Count - 1; i++)
{
    j = rnd.Next(0, dt1.Rows.Count - 1);
    DataRow row = dt1.Rows[j];
    dt.ImportRow(row);
}

Their is no syntax error but when I run my code where I further access dt I some of same rows get imported twice. What am I doing wrong here?

Craig W.
  • 17,838
  • 6
  • 49
  • 82
Omkar Frozen
  • 157
  • 9
  • If I had to guess, I'd say the thing you're doing wrong is trying to take a DataRow that belongs to one DataTable and put it in another DataTable (the error message is pretty clear). You likely need to create a *new* row, add it to `dt` then *remove* the row from `dt1`. – Craig W. Jun 11 '16 at 13:51
  • int j; for (int i = 0; i < dt1.Rows.Count - 1; i++) { j = rnd.Next(0, dt1.Rows.Count - 1); DataRow row = dt1.Rows[j]; dt.ImportRow(row); // dt.Rows.Add(row); } this worked for me – Omkar Frozen Jun 11 '16 at 13:53
  • But unfortunately it did not shuffle the datatable but rather imported same rows multiple time – Omkar Frozen Jun 11 '16 at 13:54
  • Why wouldn't you get the same rows twice? You never remove the row from `dt1` and you generate a random number. So you're generating the same random number more than once. "Random" doesn't mean "unique every time." – Craig W. Jun 11 '16 at 14:05
  • Please check this http://stackoverflow.com/a/7801754/311255 – SelvaS Jun 11 '16 at 14:10

3 Answers3

1

DataRow can only belong to a one DataTable, create a new Row with the values from existing DataRow.

dt.Rows.Add(row.ItemArray);

Or

dt.ImportRow(row);

Update:

Another approach to randomize any collection (From this Link).

public static class Extensions
{

    private static Random random = new Random();

    public static IEnumerable<T> OrderRandomly<T>(this IEnumerable<T> items)        
    {               
        List<T> randomly = new List<T>(items);

        while (randomly.Count > 0)          
        {

            Int32 index = random.Next(randomly.Count);          
            yield return randomly[index];

            randomly.RemoveAt(index);           
        }       
    }   
}

Now you can randomize any collection just by calling this extension function.

var dt = dt1.AsEnumerable()
            .OrderRandomly()
            .CopyToDataTable();

Check this Example

Hari Prasad
  • 16,716
  • 4
  • 21
  • 35
0

Here's an extension method I wrote for datatables. In a static DataTableExtensions Class

public static DataTable Shuffle(this DataTable table) {
    int n = table.Rows.Count;
    List<DataRow> shuffledRows = new List<DataRow>();
    foreach (DataRow row in table.Rows) {
        shuffledRows.Add(row);
    }

    while (n > 1) {
        n--;
        int k = Random.Range(0, n + 1);
        DataRow value = shuffledRows[k];
        shuffledRows[k] = shuffledRows[n];
        shuffledRows[n] = value;
    }

    DataTable shuffledTable = table.Clone();
    foreach (DataRow row in shuffledRows) {
        shuffledTable.ImportRow(row);
    }

    return shuffledTable;
}

Probably not most efficient but it works.

use:

DataTable shuffledTable = otherDataTable.Shuffle();
Adam B
  • 3,662
  • 2
  • 24
  • 33
0

here is my solution.

Just pass your table to the function and function will randomize the rows within the table.

public static void RandomizeTable(DataTable RPrl)
{
    System.Security.Cryptography.RNGCryptoServiceProvider provider = new System.Security.Cryptography.RNGCryptoServiceProvider();
    int n = RPrl.Rows.Count;
    while (n > 1)
    {
        byte[] box = new byte[1];
        do
        {
            provider.GetBytes(box);
        }
        while (!(box[0] < n * (System.Byte.MaxValue / n)));

        int k = (box[0] % n);
        n--;
        object[] tmp = RPrl.Rows[k].ItemArray;
        RPrl.Rows[k].ItemArray = RPrl.Rows[n].ItemArray;
        RPrl.Rows[n].ItemArray = tmp;
    }
}
hsCode
  • 469
  • 4
  • 11