Looping through the rows, updating the values as you go is definitely a solution, and a quite easy one:
foreach (DataRow row in table.Rows)
{
if (row.IsNull("foo")) row["foo"] = "-";
if (row.IsNull("bar")) row["bar"] = "-";
row["date"] = ((DateTime)row["date"]).Date;
}
Alternatively, you could create new columns in the table, using expressions to autogenerate content:
table.Columns.Add("foo_dash", typeof(string), "IsNull(foo, '-')");
table.Columns.Add("bar_dash", typeof(string), "IsNull(bar, '-')");
(I don't know the date functions in ADO.NET so you will have to figure the last one out yourself.)
You have tagged your post ASP.NET, so I guess it is reasonable to assume that you are going to bind your DataTable
to some multi-record data control (GridView
, Repeater
, etc). If this is the case, it might be better to do the transformations during databinding instead:
protected void theGrid_OnRowDataBound(object sender, GridViewRowEventArgs e)
{
var data = e.DataItem as DataRowView;
if (data != null)
{
if (data.Row.IsNull("foo")) e.Row.Cells[0] = "-";
if (data.Row.IsNull("bar")) e.Row.Cells[0] = "-";
}
}
While this seems to require a bit more code, it also gives you more flexibility. Example:
if (data.Row.IsNull("importantField")) e.Row.CssClass = "error";
In a GridView
, the date can be formatted using a DataFormatString
in the column declaration:
<asp:BoundField DataField="data" DataFormatString="{0:d}" />
Similar when databinding a Repeater
:
<%# Eval("date", "{0:d}") %>
One way to do this would be to go through the table, building a HashSet<string>
that contains the combined column values you're interested in. If you try to add a string that's already there, then you have a duplicate row. Something like:
HashSet<string> ScannedRecords = new HashSet<string>();
foreach (var row in dtCSV.Rows)
{
// Build a string that contains the combined column values
StringBuilder sb = new StringBuilder();
foreach (string col in columns)
{
sb.AppendFormat("[{0}={1}]", col, row[col].ToString());
}
// Try to add the string to the HashSet.
// If Add returns false, then there is a prior record with the same values
if (!ScannedRecords.Add(sb.ToString())
{
// This record is a duplicate.
}
}
That should be very fast.
Best Answer
I believe you intended it more this way:
You always accessed your first row in your dataset.