How to create multidimensional dictionary in aspx from DataTable? - c#

DataTable users_table = db.GetRows("SELECT * FROM users");
int rowCount = users_table.Rows.Count;
int columnCount = users_table.Columns.Count;
Dictionary<int, Dictionary<string, string>> baskets = new Dictionary<int, Dictionary<string, string>>();
for (int i = 0; i < rowCount; i++)
{
baskets.Add(i, new Dictionary<string, string>());
for (int j = 0; j < columnCount; j++)
{
var colName = (users_table.Columns[i].ColumnName).ToString();
var colValue = users_table.Rows[i][j].ToString();
baskets[i].Add(colName, colValue);
Response.Write(baskets[i]["user_id"].ToString());
}
}
This is the error i got.
ArrgumentException was unhandled by user code at baskets[i].Add(colName, colValue);
An exception of type 'System.ArgumentException' occurred in mscorlib.dll but was not handled in user code
Additional information: An item with the same key has already been added.
What I'm doing wrong? I debug it and value of "i", "colName" and "colValue" is correct. Don't know why it's giving me error.
I'm newbie in .net programming

In your inner loop i does not change and therefore the value of colName does not change. As a result you're adding the same key each time through:
var colName = (users_table.Columns[i].ColumnName).ToString();
baskets[i].Add(colName, colValue);
Most likely you meant to grab the name from Columns[j] instead of Columns[i] and this is a "second pair of eyes" problem.
FWIW, you can avoid this by using more descriptive counter variable names instead of the "traditional" i and j. Your code from the question translates to, which IMHO is easier to notice as "something's wrong with Columns[row]":
for (int row = 0; i < rowCount; row++)
{
baskets.Add(row, new Dictionary<string, string>());
for (int col = 0; col < columnCount; col++)
{
var colName = (users_table.Columns[row].ColumnName).ToString();
var colValue = users_table.Rows[row][col].ToString();
baskets[row].Add(colName, colValue);
Response.Write(baskets[row]["user_id"].ToString());
}
}
Side note 1: DataTable.ColumnName is already a string, so your call to ToString() above is unnecessary.
Side note 2: Unless the "user_id" column is column 0, the Response.Write line is going to fail. Was this perhaps intended to be outside of the inner loop, or maybe just added for debugging purposes?
Side note 3: You can also keep a reference to the inner dictionary instead of using the indexer baskets[row] each time through the inner loop. Yes, this probably is a difference of microseconds, but:
for (int row = 0; i < rowCount; row++)
{
var colDic = new Dictionary<string, string>();
baskets.Add(row, colDic);
for (int col = 0; col < columnCount; col++)
{
var colName = users_table.Columns[row].ColumnName;
var colValue = users_table.Rows[row][col].ToString();
colDic.Add(colName, colValue);
}
}

Just remove the line
baskets.Add(i, new Dictionary<string, string>());
Because this adds an integer to the Dictionary that is 0 in the first iteration and then when it reaches to baskets[i].Add(colName, colValue); the dictionary has already added 0 in the key and would not be able to add the same item again. So removing that line will do make your code something like this
for (int i = 0; i < rowCount; i++)
{
for (int j = 0; j < columnCount; j++)
{
var colName = users_table.Columns[j].ColumnName;
var colValue = users_table.Rows[i][j].ToString();
baskets[i].Add(colName, colValue);
Response.Write(baskets[i]["user_id"].ToString());
}
}
might do the trick for you

Related

Add row to specific column by header name/text

I have a column named "HeaderText_Name" and in this column, I want to add a row that has the text "Row" under that column.
I attempted to write some pseudo-code for it
databaseGridView.Rows["HeaderText_Name"].Add("Row");
If I do
databaseGridView.Rows.Add("Row");
It adds it to the first column no matter what. I also can't do something like
databaseGridView.Rows.Add("","","Row");
Then it adds blanks to the first two columns and I also don't know how which index the column is. So I would be more helpful if it was by Name or text.
Here is the actual code I have so far..
for (int i = 0; i < completeInfoMatches.Count; i++) {
databaseGridView.Rows.Add();
databaseGridView.Rows[0].Cells[e.Node.Text].Value = completeInfoMatches[i].Groups[1].ToString();
}
Now, completeInfoMatches has more than 1 match because it's regex. How can I change the 0 to make it work?
UPDATE
int currentRowIndex = 0;
databaseGridView.Columns.Add(e.Node.Text.Replace(" ", string.Empty), e.Node.Text);
for (int i = 0; i < completeInfoMatches.Count; i++) {
databaseGridView.Rows.Add();
databaseGridView.Rows[currentRowIndex].Cells[e.Node.Text.Replace(" ", string.Empty)].Value = completeInfoMatches[i].Groups[1].ToString();
currentRowIndex = currentRowIndex + 1;
}
I'm getting a lot of extra blank rows because of Row.Add
Try something like this:
foreach(int i = 0; i < completeInfoMatches.Count; i++){
var index = databaseGridView.Rows.Add();
databaseGridView.Rows[index].Cells[e.Node.Text].Value = completeInfoMatches[i].Groups[1].ToString();
}
With the help of #Forlani ...
int currentRowIndex = 0;
int actualRowIndex = databaseGridView.Rows.Count;
for (int i = 0; i < completeInfoMatches.Count; i++) {
var index = 0;
if (actualRowIndex < completeInfoMatches.Count) {
index = databaseGridView.Rows.Add();
}
databaseGridView.Rows[currentRowIndex].Cells[e.Node.Text.Replace(" ", string.Empty)].Value = completeInfoMatches[i].Groups[1].ToString();
currentRowIndex = currentRowIndex + 1;
}

Do you always have to start at the index zero when writing a 2D list?

I want to fill in a 2Dlist, but start at the third position [2]. Is this somehow possible?
A short code for understanding what i mean:
List<List<string>> List2D = new List<List<string>>();
for (int i = 0; i < 5; i++)
{
List2D[2].Add("i")
}
I get the following error:
Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index
EDIT: Any idea how to fill in a 4D list?
List<List<List<List<string>>>> List4D = new List<List<List<List<string>>>>();
for (int i = 0; i < List1.Count; i++)
{
List<List<List<string>>> List3D = new List<List<List<string>>>();
for (int j = 0; j < List2.Count; j++)
{
List<List<string>> List2D = new List<List<string>>();
for (int k = 0; k < List3.Count; k++)
{
List<string> Lijst1D = new List<string>();
List2D.Add(Lijst1D);
}
List3D.Add(List2D);
}
List4D.Add(List3D);
}
So later I can call: List4D[2][3][0].Add("test");
Since you just created your List2D and not added any nested list into it, you can't access its third element (there is nothing there).
You have to add some items first:
List<List<string>> List2D = new List<List<string>>();
List2D.Add(new List<string>());
List2D.Add(new List<string>());
List2D.Add(new List<string>());
for (int i=0; i<5; i++)
{
List2D[2].Add("i")
}
Update
Well, core idea of filling that list remains the same: if you want to access List4D[2][3][0] - first you need to fill all of lists in "path".
You can do it something like this:
List<List<List<List<string>>>> List4D = new List<List<List<List<string>>>>();
int i1 = 2, i2 = 3, i3 = 0;
for (int i = 0; i <= Math.Max(i1, 1); i++)
List4D.Add(new List<List<List<string>>>());
for (int i = 0; i <= Math.Max(i2, 1); i++)
List4D[i1].Add(new List<List<string>>());
for (int i = 0; i <= Math.Max(i3, 1); i++)
List4D[i1][i2].Add(new List<string>());
List4D[i1][i2][i3].Add("test");
Frankly, idea of 4D list looks a little bit "syntetic". In real application probably it is not the best data structure because of clumsy addressing.

Values in a Dictionary are getting replaced by last value in C#

I have a Dictionary type variable where I'm keeping "string" type key and "List " type values.
The problem is, in case of loop all the previous values are getting replaced by the last value.
Why this happens?
List<IWebElement> indicationsElement = ReturnIndicationList();
drugsDB = new List<string>();
for (int i = 0; i < indicationsElement.Count;i++ )
{
string key = indicationsElement[i].Text.ToString();
dt = ZittarPatt.getDrugsByIndication(ClientName, key);
drugsDB.Clear();
for (int k = 0; k < dt.Rows.Count; k++)
{
drugsDB.Add(dt.Rows[k].ItemArray[3].ToString().Trim());
}
drugsByindicationDictionary.Add(key, drugsDB);
}
You're adding the same reference every iteration instead of adding new instance of List<string>.
Every time you use .Clear it clears all the entries at drugsByindicationDictionary which are already the same entry.
Thus, only the last addition to drugsDB will be saved. (No .Clear is used at the end)
You should do the following code:
List<IWebElement> indicationsElement = ReturnIndicationList();
for (int i = 0; i < indicationsElement.Count;i++ )
{
string key = indicationsElement[i].Text.ToString();
dt = ZittarPatt.getDrugsByIndication(ClientName, key);
var drugsDB = new List<string>();
for (int k = 0; k < dt.Rows.Count; k++)
{
drugsDB.Add(dt.Rows[k].ItemArray[3].ToString().Trim());
}
drugsByindicationDictionary.Add(key, drugsDB);
}
Change drugsDB.Clear(); to drugsDB = new List<string>();

C# multi-dimension array sort based on user input

How can I sort a 2D array in C#
I have looked at other answers to this question but they don't do exactly what I need.
The array is variable height * 5 across
The array holds strings
I need the array sorted based on either column, for example sort in alphabetical the third column, however all other columns must be updated.
Does anyone know of a quick and easy solution?
My code is a mess, here is a shortened version:
string[,] tmp = new string[2, 3];//this is filled with strings
string y = Console.ReadLine();
int x = Convert.ToInt32(y);
// sort tmp based on x column
How do I sort a two-dimensional array in C#? contains a possible solution to this by reading your data into a datatable and then using the object's methods to sort:
// assumes stringdata[row, col] is your 2D string array
DataTable dt = new DataTable();
// assumes first row contains column names:
for (int col = 0; col < stringdata.GetLength(1); col++)
{
dt.Columns.Add(stringdata[0, col]);
}
// load data from string array to data table:
for (rowindex = 1; rowindex < stringdata.GetLength(0); rowindex++)
{
DataRow row = dt.NewRow();
for (int col = 0; col < stringdata.GetLength(1); col++)
{
row[col] = stringdata[rowindex, col];
}
dt.Rows.Add(row);
}
// sort by third column:
DataRow[] sortedrows = dt.Select("", "3");
// sort by column name, descending:
sortedrows = dt.Select("", "COLUMN3 DESC");
So first we'll want to convert the multi-dimensional array into a sequence of single-dimensional arrays representing the rows, so that each row can be manipulated as a unit:
public static IEnumerable<T[]> GetRows<T>(T[,] array)
{
for (int i = 0; i < array.GetLength(0); i++)
{
T[] row = new T[array.GetLength(1)];
for (int j = 0; j < row.Length; j++)
{
row[j] = array[i, j];
}
yield return row;
}
}
Then we'll also need a method that does the reverse to get a multi-dimensional array back when we're done:
public static T[,] ToMultiDimensionalArray<T>(T[][] rows)
{
T[,] output = new T[rows.Length, rows[0].Length];
for (int i = 0; i < rows.Length; i++)
for (int j = 0; j < rows[0].Length; j++)
{
output[i, j] = rows[i][j];
}
return output;
}
Now we just need to sort a sequence of arrays, and Linq makes this quite easy:
tmp = ToMultiDimensionalArray(GetRows(tmp)
.OrderBy(row => row[2]).ToArray());

Get Cell Value from a DataTable in C#

Here is a DataTable dt, which has lots of data.
I want to get the specific Cell Value from the DataTable, say Cell[i,j]. Where,
i -> Rows and j -> Columns. I will iterate i,j's value with two forloops.
But I can't figure out how I can call a cell by its index.
Here's the code:
for (i = 0; i <= dt.Rows.Count - 1; i++)
{
for (j = 0; j <= dt.Columns.Count - 1; j++)
{
var cell = dt.Rows[i][j];
xlWorkSheet.Cells[i + 1, j + 1] = cell;
}
}
The DataRow has also an indexer:
Object cellValue = dt.Rows[i][j];
But i would prefer the strongly typed Field extension method which also supports nullable types:
int number = dt.Rows[i].Field<int>(j);
or even more readable and less error-prone with the name of the column:
double otherNumber = dt.Rows[i].Field<double>("DoubleColumn");
You probably need to reference it from the Rowsrather than as a cell:
var cellValue = dt.Rows[i][j];
You can iterate DataTable like this:
private void button1_Click(object sender, EventArgs e)
{
for(int i = 0; i< dt.Rows.Count;i++)
for (int j = 0; j <dt.Columns.Count ; j++)
{
object o = dt.Rows[i].ItemArray[j];
//if you want to get the string
//string s = o = dt.Rows[i].ItemArray[j].ToString();
}
}
Depending on the type of the data in the DataTable cell, you can cast the object to whatever you want.
To get cell column name as well as cell value :
List<JObject> dataList = new List<JObject>();
for (int i = 0; i < dataTable.Rows.Count; i++)
{
JObject eachRowObj = new JObject();
for (int j = 0; j < dataTable.Columns.Count; j++)
{
string key = Convert.ToString(dataTable.Columns[j]);
string value = Convert.ToString(dataTable.Rows[i].ItemArray[j]);
eachRowObj.Add(key, value);
}
dataList.Add(eachRowObj);
}
You can call the indexer directly on the datatable variable as well:
var cellValue = dt[i].ColumnName
If I have understood your question correctly you want to display one particular cell of your populated datatable? This what I used to display the given cell in my DataGrid.
var s = dataGridView2.Rows[i].Cells[j].Value;
txt_Country.Text = s.ToString();
Hope this helps

Categories