I have a datatable like this:
Column1
Column2
Column3
Name1
Code111
12550
Name2
Code112
12551
Name3
Code113
12552
Name4
Code114
12553
I want to convert it to a dictionary where the first column is the key. The combination of the second column with lowercase letters and the third column is the value.
Expected result:
key
value
Name1
code111_12550
Name2
code112_12551
Name3
code113_12552
Name4
code114_12553
This is my code:
DataTable dt = new DataTable();
dt.Columns.Add("Column1");
dt.Columns.Add("Column2");
dt.Columns.Add("Column3");
dt.Rows.Add("Name1", "Code111", 12550);
dt.Rows.Add("Name2", "Code112", 12551);
dt.Rows.Add("Name3", "Code113", 12553);
dt.Rows.Add("Name4", "Code114", 12554);
Dictionary<string,string> dic = new Dictionary<string,string>();
for (int i = 0; i < dt.Rows.Count; i++)
{
string _k = dt.Rows[i][0].ToString();
string _v = dt.Rows[i][1].ToString().ToLower()+ "_" +
dt.Rows[i][2].ToString();
dic.Add(_k, _v);
}
Is there a better way to convert a datatable to a dictionary? For example, can I use Linq?
You can use the linq.enumerable.todictionary to convert the DataTable into a Dictionary:
var _dic = dt.AsEnumerable()
.ToDictionary<DataRow, string, string>(row => row.Field<string>(0),
row => row.Field<string>(1).ToLower() + "_" + row.Field<string>(2) );
Since .NET 6 is the oldest supported .NET Core version, one can use ranges to reduce the code to this :
var dict=dt.AsEnumerable().ToDictionary(
r=>r[0],
r=>String.Join('_',r.ItemArray[1..]));
If the values need to be lowercase, ToLower() can be called after joining.
var dict=dt.AsEnumerable().ToDictionary(
r=>r[0],
r=>String.Join('_',r.ItemArray[1..])?.ToLower());
Related
I have a very big csv file like this (more than 12K rows) ;
Comment, DateTime Name, Age, Class, Place, --> these are the header columns
Good, 03/10/2022, John, 12, 3, UK,
Bad, 12/10/2022, Tom, 15, 2, US
This is a generalized example which shows column names. But it will be more than this columns some times.
I am reading it as shown below
List<string> lines = File.ReadAllLines(System.IO.Path.ChangeExtension(FileNameWithPath, ".csv")).ToList();
I need a datatable from the above mentioned csv file but i DO NOT want Comment and Place columns in the datatable.
Can anybody show me how we can achieve this ?
Column datatypes :
DateTime --> typeof(datetime)
Name --> typeof(string)
Age --> typeof(double?)
Class --> typeof(int)
You can remove the columns using DataColumnCollection.Remove() after converting from the list to a datatable.
dt.Remove("Comments")
public static DataTable CSVtoDataTable(string filePath)
{
DataTable dtData = new DataTable();
using (StreamReader sReader = new StreamReader(filePath))
{
string[] columnHeader = sReader.ReadLine().Split(',');
foreach (string header in columnHeader)
{
dtData.Columns.Add(header);
}
while (!sReader.EndOfStream)
{
string[] rows = sReader.ReadLine().Split(',');
DataRow drRow = dtData.NewRow();
for (int i = 0; i < columnHeader.Length; i++)
{
drRow[i] = rows[i];
}
dtData.Rows.Add(drRow);
}
}
dtData.Columns.Remove("Comment");
dtData.Columns.Remove("Place");
return dtData;
}
I need to join two datatable's and select all values from both table because d1 columns are dynamic i have tried with below code and getting the join value but when i select it shows in 2 DataRows it should be in one row
DataTable dtRtn = new DataTable();
var result = from d1 in dtFormData.AsEnumerable()
join d2 in dtResponderDetails.AsEnumerable()
on d1.Field<string>("ResponderId") equals d2.Field<string>("EmployeeId")
select new { d1,d2};
I need both d1 and d2 joined result to be copied to dtRtn table
Edit
I have searched but there is not straight forward answer for and all answers shows how to select specific columns
Please help thanks
You will need to first dynamically add the columns from dtFormData and dtResponderDetails to dtRtn. Then you can iterate through the results of your LINQ query and create new DataRow objects for each.
Here is a quick stab at the necessary code you would need to add to what you currently have:
// Step 1: Add all columns from your two DataTables to dtRtn
// (with a prefix to avoid naming collisions)
DataTable dtRtn = new DataTable();
CopyColumns(dtFormData, dtRtn, "FormData.");
CopyColumns(dtResponderDetails, dtRtn, "ResponderDetails.");
// Step 2: Build a collection containing all of the values for this result
var numFormColumns = dtFormData.Columns.Count;
var numResponderColumns = dtResponderDetails.Columns.Count;
foreach(var row in result) {
var targetRow = new List<object>();
PopulateRows(row.d1, numFormColumns, targetRow);
PopulateRows(row.d2, numResponderColumns, targetRow);
// Pass the values in as an array, which will convert it to a new DataRow
dtRtn.Rows.Add(targetRow.ToArray());
}
//...
private void CopyColumns(DataTable sourceTable, DataTable targetTable, string rowPrefix)
{
foreach (DataColumn column in sourceTable.Columns)
{
var rowName = String.Format("{0}{1}", rowPrefix, column.ColumnName);
targetTable.Columns.Add(rowName, column.DataType);
}
}
void PopulateRows(DataRow sourceRow, int numColumns, List<object> targetRow)
{
for(var i = 0; i < numColumns; i++) {
targetRow.Add(sourceRow[i]);
}
}
I have a data table like below:
field_1 field_1 field_2 field_2
1 2 3 4
Now I want to convert it to:
field_1 field_2
1 3
2 4
using c#.
I tried to use this code to add columns header, but i cannot import rows to it:
private DataTable test(DataTable dispTable)
{
DataTable outputTbl = new DataTable();
int index = 0;
// Get list values of datatable
var stringArr = dispTable.Rows[0].ItemArray.Select(x => x.ToString()).ToArray();
// Add column headers
outputTbl.Columns.Add("hidden_col");
foreach (DataColumn dc in dispTable.Columns)
{
if (index % 2 == 0) //dispTable always contain 1 pair of column with same name
{
// Create a new column
outputTbl.Columns.Add(dc.ColumnName);
}
// Moving to next col
index++;
}
return outputTbl;
}
How to do it?
Are you looking for something like this?
public void Test(DataTable indata)
{
DataTable outdata = new DataTable();
ArrayList columns = new ArrayList();
// create a outdatatable to contain only distinct coulmn names
foreach (DataColumn dc in indata.Columns)
{
if (!columns.Contains(dc.ColumnName))
{
columns.Add(dc.ColumnName);
outdata.Columns.Add(dc);
}
}
foreach (DataRow dr in indata.Rows)
{
DataRow outdr = outdata.NewRow();
outdr["field_1"] = dr["field_1"] + " " +dr["field_1"]; // dont think it is possible to have two coulmns of same name
outdr["field_2"] = dr["field_2"] + " " + dr["field_2"];
}
}
method1:
public void method1(DataTable ServerGroupIds)
{
obj.method2(ServerGroupIds);
}
method2 :
public static void method2(string[] servergroups)
{
obj.Message = userName + " has Un-Restricted the Project.";
}
Now I want to pass the DataTable values into the method2 String[] servergroups
How can I pass my DataTable values into an array of string values?
Sorry, Forget to mention I have 2 columns in my DataTable. !st column is ProjectId and Second Column is Server Group Id. Now I need only ServerGroup Id's in my array of string
Try this
public void method1(DataTable ServerGroupIds)
{
string [] serverGroups = ServerGroupIds.AsEnumerable().Select(t => t.Field<string>("ID")).ToArray<string>();
obj.method2(serverGroups );
}
Don't forget to include System.Linq
in t.Field<string>("ID"). Replace "ID" with the name of the column in the data table you want to put into the array
For a single row you can do this:
var rowAsString = string.Join(", ", ServerGroupIds.Rows[0].ItemArray);
Now add all the rows (by looping through your DataTable) rowAsString to a list:
List<string> list = new List<string>();
for (int i = 0; i < ServerGroupIds.Rows.Count; i++)
{
string rowAsString = string.Join(", ", ServerGroupIds.Rows[i].ItemArray);
list .Add(rowAsString );
}
string[] array = list.ToArray();
And pass to method2:
obj.method2(array);
I'm having problems with a DataTable.Select() where the matching values might contain leading spaces and need to be trimmed correctly to return the correct amount of records.
Currently my code is returning less records as the matching fails because of unwanted characters.
How do you handle DataTable.Select as the example SQL below suggests?
SELECT * FROM Table WHERE LTRIM(FullName) = ' Joe Smith'
I' tried
dataTable.Select("LTRIM(FullName) = ' Joe Smith'");
but it failed.
Any ideas?
I would suggest to use Linq-To-DataSet instead, it makes it a lot clearer and easier to maintain:
var rows = from row in dataTable.AsEnumerable()
where row.Field<string>("FullName").Trim() == "Joe Smith"
select row;
If you want to use LTRIM instead, you just have to replace Trim with TrimStart.
if you want an array or list, use ToArray or ToList, e.g.
DataRow[] rowsArray = rows.ToArray();
or a DataTable
dataTable = rows.CopyToDataTable();
Edit: if you insist on using DataTable.Select or you can't use linq, this should work(LTRIM is not supported):
rowsArray = dataTable.Select("TRIM(FullName) = 'Joe Smith'");
Give this a try:
string searchTerm = " Joe Smith";
string expression = String.Format("TRIM(FullName) = '{0}'", searchTerm.Trim());
dataTable.Select(expression);
DataTable excelData = objGetExcelData.DataExcel(objEntities.StrFilePath, ConfigSettings.GetAppConfigValue("select * from sheet1"));
StringBuilder strInput = new StringBuilder();
DataView view = new DataView(excelData);
DataTable distinctValues = view.ToTable(true, "GROUP_NAME");
if (distinctValues.Rows.Count > 0)
{
for (int i = 0; i < distinctValues.Rows.Count; i++)
{
strGroupName = Convert.ToString(distinctValues.Rows[i]["GROUP_NAME"]);
foreach (DataRow item in excelData.Select("GROUP_NAME = '" + strGroupName + "'"))
{
strInput.Append(Convert.ToString(item[0]));
strInput.Append("~");
strInput.Append(Convert.ToString(item[1]));
strInput.Append(",");
strDasID = Convert.ToString(item[0]);
}
}
}