Ako rozhádzať DataTable
Nedávno som narazil na to, že potrebujem zobraziť nejaké dáta v náhodnom poradí pri každom zobrazení stránky.
MS SQL riešenie
Najprv som to chcel riešiť na úrovni MS SQL databázy.
MS SQL má funkciu RAND ktorá je ale dosť nepraktická a na tento účel nepoužiteľná. Napriek tomu existuje pomerne jednoduché riešenie:
SELECT * FROM table ORDER BY NEWID()
Funkcia NEWID vygeneruje náhodný identifikátor pre každý riadok. Takže vďaka ORDER BY klauzule budú výsledky vždy v inom poradí. Dá sa to použiť aj v kombinácii s TOP klauzulou, napr.:
SELECT TOP(10) * FROM table WHERE cid < 1000 ORDER BY NEWID()
Nevýhodou je, že NEWID() sa generuje vždy pre každý jeden riadok celej tabuľky. V každom prípade je toto riešenie veľmi rýchle.
.NET riešenie
Ďaľšou možnosťou je rozhádzať výsledky na úrovni aplikácie.
Nasledujúca statická metóda dostane na vstup parameter typu DataTable a vráti nový DataTable s náhodne poprehadzovanými riadkami:
public static DataTable Randomize(DataTable dt)
{
if (dt == null) throw new ArgumentNullException("dt");
dt.AcceptChanges();
//Vytvorím novú DataTable s rovnakou štruktúrou
DataTable dtnew = dt.Clone();
//Vytvorím nový DataView nad tabuľkou dt
DataView dv = dt.DefaultView;
Random r = new Random();
int randomIndex = 0;
while (dv.Count > 0)
{
//Vyberiem náhodný index (riadok)
randomIndex = r.Next(0, dv.Count);
//Pridám vybraný riadok do novej DataTable
dtnew.Rows.Add(dv[randomIndex].Row.ItemArray);
//Nastavím vybraný riadok zo starej DataTable na "vymazaný"
dv.Delete(randomIndex);
}
//Zruším "vymazanie" riadkov
dt.RejectChanges();
dv = null;
return dtnew;
}
Komentáre by mali byť jasné. Výhodou tohto prístupu je, že sa dá použiť viackrát nad už vytiahnutými dátami z DB. Taktiež je menej zaťažená databáza a dá sa použiť kedykoľvek ad-hoc.
Implementácia pre .NET 3.5
Ak používate .NET 3.5, môžete si túto metódu naimplementovať ako extension metódu nad DataTable:
public static class DataUtils
{
public static DataTable Randomize(this DataTable dt)
{
dt.AcceptChanges();
//Vytvorím novú DataTable s rovnakou štruktúrou
DataTable dtnew = dt.Clone();
//Vytvorím nový DataView nad tabuľkou dt
DataView dv = dt.DefaultView;
Random r = new Random();
int randomIndex = 0;
while (dv.Count > 0)
{
//Vyberiem náhodný index (riadok)
randomIndex = r.Next(0, dv.Count);
//Pridám vybraný riadok do novej DataTable
dtnew.Rows.Add(dv[randomIndex].Row.ItemArray);
//Nastavím vybraný riadok zo starej DataTable na "vymazaný"
dv.Delete(randomIndex);
}
//Zruším "vymazanie" riadkov
dt.RejectChanges();
dv = null;
return dtnew;
}
}
Potom môžeme použiť nasledovný jednoduchý zápis:
DataTable random = dt.Randomize();
Ak máte iné skúsenosti s náhodným poradím dát, podeľte sa o ne v diskusii.
Update 6. 7. 2009
Dnes ma napadlo aj ďalšie riešenie, ako náhodne poprehadzovať riadky DataTable.
Najprv pridám nový stĺpec, dám doňho náhodné hodnoty a potom to podľa neho zotriedim. Na generovanie náhodných hodnôt použijem metódu Guid.NewGuid(), ktorá vždy vráti iný a náhodný identifikátor.
Tu je teda ďalšie riešenie:
public static class DataUtils
{
public static DataTable RandomizeEx(this DataTable dt)
{
if (dt.Rows.Count == 0) return null;
//vytvorim unikatny nazov stlpca, ktory bude obsahovat "nahodne" retazce
string randomColumn = string.Format("Random_{0}", Guid.NewGuid());
//pridam stlpec do tabulky
dt.Columns.Add(randomColumn, typeof(string));
//pre kazdy riadok pridam nahodny retazec - Guid
for (int i = 0; i < dt.Rows.Count; i++)
{
dt.Rows[i][randomColumn] = Guid.NewGuid().ToString();
}
//dam zotriedit DataView podla stlpca s nahodnymi hodnotami
dt.DefaultView.Sort = randomColumn;
//vratim novu DataTable zo zotriedeneho DataView
return dt.DefaultView.ToTable();
}
}
Tento článok zahŕňa témy:
MS SQL, Randomize, System.Data.DataTable, ASP.NET, C#, RAND(), NEWID(), Extension Methods, ASP
K tomuto článku zatiaľ nie sú žiadne komentáre. Buďte prvý. ;]
Poraďte sa s nami o službách, ktoré potrebujete. My vám pripravíme konkrétnu cenovú ponuku.
Kontaktujte nás