I have a DataTable like this:
DataTable dataTable = new DataTable();
dataTable.Columns.Add("A", typeof(string));
dataTable.Columns.Add("B", typeof(string));
dataTable.Columns.Add("C", typeof(string));
List<string> headersToSkip = new List<string>() { "A", "B" };
Dictionary<string, string> headersToReplace = new Dictionary<string, string>() { { "C", "D" } };
IEnumerable<DataColumn> queriableColumms = dataTable.Columns.Cast<DataColumn>().AsQueryable().ToList();
var toBeRemoved = from DataColumn column in queriableColumms
where headersToSkip != null && headersToSkip.Contains(column.ColumnName)
select column;
foreach (DataColumn column in toBeRemoved)
{
dataTable.Columns.Remove(column);
}
if (headersToReplace != null)
{
foreach (KeyValuePair<string, string> kvp in headersToReplace)
{
foreach (DataColumn column in dataTable.Columns.Cast<DataColumn>().AsQueryable().ToList())
{
if (column.ColumnName.Equals(kvp.Key))
column.ColumnName = kvp.Value;
}
}
}
Is it possible to remove columns in DataTable and replace column names with some other column names efficiently.
By efficiently, if you mean with less code, you could do the following.
To Remove Columns
List<string> headersToSkip = new List<string>() { "A", "B" };
foreach(var header in headersToSkip)
{
dataTable.Columns.Remove(header);
}
To Rename Columns,
Dictionary<string, string> headersToReplace = new Dictionary<string, string>() { { "C", "D" } };
foreach(var header in headersToReplace)
{
dataTable.Columns[header.Key].ColumnName = header.Value;
}
Related
I have four tables (employees, allowances,deductions and Ajenda these are main tables , when i save employees financial details i save them in a different tables as image .
I want to display the employees detail and financial details in a horizontally way .
I'm using C# and SQLServer 2012 .
first table contains employees main details , second contain employees id with there allowances and other tables .
My tables
Here is my code before somebody closes it again. I decided not to use group since there would be a lot of left outer joins which would complicate solution. Decided just to create a table and then add the data directly to the results table.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
DataTable employees = new DataTable();
employees.Columns.Add("empID", typeof(int));
employees.Columns.Add("emp_name", typeof(string));
employees.Columns.Add("emp_tele", typeof(string));
employees.Rows.Add(new object[] { 1, "David", "025896325" });
employees.Rows.Add(new object[] { 2, "John", "856985658" });
employees.Rows.Add(new object[] { 3, "Micheal", "654687887" });
DataTable allowances = new DataTable();
allowances.Columns.Add("empID", typeof(int));
allowances.Columns.Add("allow_name", typeof(string));
allowances.Columns.Add("allow_Amount", typeof(int));
allowances.Rows.Add(new object[] { 1, "allow1", 100 });
allowances.Rows.Add(new object[] { 1, "allow2", 200 });
allowances.Rows.Add(new object[] { 1, "allow3", 300 });
allowances.Rows.Add(new object[] { 2, "allow1", 100 });
allowances.Rows.Add(new object[] { 2, "allow2", 200 });
DataTable deductions = new DataTable();
deductions.Columns.Add("empID", typeof(int));
deductions.Columns.Add("Dedu_name", typeof(string));
deductions.Columns.Add("Dedu_Amount", typeof(int));
deductions.Rows.Add(new object[] { 1, "ded1", 10 });
deductions.Rows.Add(new object[] { 1, "ded2", 5 });
deductions.Rows.Add(new object[] { 2, "ded1", 10 });
DataTable ajenda = new DataTable();
ajenda.Columns.Add("empID", typeof(int));
ajenda.Columns.Add("ajenda_name", typeof(string));
ajenda.Columns.Add("ajenda_Amount", typeof(int));
ajenda.Rows.Add(new object[] { 1, "aj1", 200 });
ajenda.Rows.Add(new object[] { 1, "aj1", 200 });
ajenda.Rows.Add(new object[] { 1, "aj2", 300 });
DataTable results = employees.Clone();
string[] allow_names = allowances.AsEnumerable().Select(x => x.Field<string>("allow_name")).Distinct().OrderBy(x => x).ToArray();
foreach (string name in allow_names)
{
results.Columns.Add(name, typeof(string));
}
string[] dedu_names = deductions.AsEnumerable().Select(x => x.Field<string>("Dedu_name")).Distinct().OrderBy(x => x).ToArray();
foreach (string name in dedu_names)
{
results.Columns.Add(name, typeof(string));
}
string[] ajenda_names = ajenda.AsEnumerable().Select(x => x.Field<string>("ajenda_name")).Distinct().OrderBy(x => x).ToArray();
foreach (string name in ajenda_names)
{
results.Columns.Add(name, typeof(string));
}
//add employees to result table
foreach(DataRow row in employees.AsEnumerable())
{
results.Rows.Add(row.ItemArray);
}
var groupAllownaces = allowances.AsEnumerable().GroupBy(x => x.Field<int>("empID"));
foreach (var group in groupAllownaces)
{
DataRow employeeRow = results.AsEnumerable().Where(x => x.Field<int>("empID") == group.Key).First();
foreach (DataRow row in group)
{
employeeRow[row.Field<string>("allow_name")] = row.Field<int>("allow_Amount");
}
}
var groupDeductions = deductions.AsEnumerable().GroupBy(x => x.Field<int>("empID"));
foreach (var group in groupDeductions)
{
DataRow employeeRow = results.AsEnumerable().Where(x => x.Field<int>("empID") == group.Key).First();
foreach (DataRow row in group)
{
employeeRow[row.Field<string>("Dedu_name")] = row.Field<int>("Dedu_Amount");
}
}
var groupAjenda = ajenda.AsEnumerable().GroupBy(x => x.Field<int>("empID"));
foreach (var group in groupAjenda)
{
DataRow employeeRow = results.AsEnumerable().Where(x => x.Field<int>("empID") == group.Key).First();
foreach (DataRow row in group)
{
employeeRow[row.Field<string>("ajenda_name")] = row.Field<int>("ajenda_Amount");
}
}
}
}
}
I have a string like this:
"Product,Price,Condition
Cd,13,New
Book,9,Used
"
Which is being passed like this:
"Product,Price,Condition\r\Cd,13,New\r\nBook,9,Used"
How could I convert it to DataTable?
Trying to do it with this helper function:
DataTable dataTable = new DataTable();
bool columnsAdded = false;
foreach (string row in data.Split(new string[] { "\r\n" }, StringSplitOptions.None))
{
DataRow dataRow = dataTable.NewRow();
foreach (string cell in row.Split(','))
{
string[] keyValue = cell.Split('~');
if (!columnsAdded)
{
DataColumn dataColumn = new DataColumn(keyValue[0]);
dataTable.Columns.Add(dataColumn);
}
dataRow[keyValue[0]] = keyValue[1];
}
columnsAdded = true;
dataTable.Rows.Add(dataRow);
}
return dataTable;
However I don't get that "connecting cells with appropriate columns" part - my cells don't have ~ in string[] keyValue = cell.Split('~'); and I obviously get an IndexOutOfRange at DataColumn dataColumn = new DataColumn(keyValue[0]);
Based on your implementation, I have written the code for you, I have not tested it. But you can use the concept.
DataRow dataRow = dataTable.NewRow();
int i = 0;
foreach (string cell in row.Split(','))
{
if (!columnsAdded)
{
DataColumn dataColumn = new DataColumn(cell);
dataTable.Columns.Add(dataColumn);
}
else
{
dataRow[i] = cell;
}
i++;
}
if(columnsAdded)
{
dataTable.Rows.Add(dataRow);
}
columnsAdded = true;
You can do that simply with Linq (and actually there is LinqToCSV on Nuget, maybe you would prefer that):
void Main()
{
string data = #"Product,Price,Condition
Cd,13,New
Book,9,Used
";
var table = ToTable(data);
Form f = new Form();
var dgv = new DataGridView { Dock = DockStyle.Fill, DataSource = table };
f.Controls.Add(dgv);
f.Show();
}
private DataTable ToTable(string CSV)
{
DataTable dataTable = new DataTable();
var lines = CSV.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries);
foreach (var colname in lines[0].Split(','))
{
dataTable.Columns.Add(new DataColumn(colname));
}
foreach (var row in lines.Where((r, i) => i > 0))
{
dataTable.Rows.Add(row.Split(','));
}
return dataTable;
}
You can split given string into flattened string array in one call. Then you can iterate through the array and populate list of objects.
That part is optional, since you can immediately populate DataTable but I think it's way easier (more maintainable) to work with strongly-typed objects when dealing with DataTable.
string input = "Product,Price,Condition\r\nCd,13,New\r\nBook,9,Used";
string[] deconstructedInput = input.Split(new string[] { "\r\n", "," }, StringSplitOptions.None);
List<Product> products = new List<Product>();
for (int i = 3; i < deconstructedInput.Length; i += 3)
{
products.Add(new Product
{
Name = deconstructedInput[i],
Price = Decimal.Parse(deconstructedInput[i + 1]),
Condition = deconstructedInput[i + 2]
});
}
public class Product
{
public string Name { get; set; }
public decimal Price { get; set; }
public string Condition { get; set; }
}
So, products collection holds 2 objects which you can easily iterate over and populate your DataTable.
Note: This requires further checks to avoid possible runtime exceptions, also it is not dynamic. That means, if you have differently structured input it won't work.
DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn(nameof(Product.Name)));
dataTable.Columns.Add(new DataColumn(nameof(Product.Price)));
dataTable.Columns.Add(new DataColumn(nameof(Product.Condition)));
foreach (var product in products)
{
var row = dataTable.NewRow();
row[nameof(Product.Name)] = product.Name;
row[nameof(Product.Price)] = product.Price;
row[nameof(Product.Condition)] = product.Condition;
dataTable.Rows.Add(row);
}
I'm converting a Data Table rows into a JSON string. Using a Javascript serializer I have generated a normal JSON string. How can we generated it as Nested string.
Current Json output
{
"PatientId":"32424",
"CustomerId":"XXXX",
"Name":"DiastolicBloodPressure",
"Value":89,
"Unit":"mmHg",
"MinValue":50,
"MaxValue":90,
"SessionElementResponseText":null
}
Expected
{
"PatientId":"32424",
"CustomerId":"XXXX",
"VitalThreshold":{
"Name":"DiastolicBloodPressure",
"Value":89,
"Unit":"mmHg",
"MinValue":50,
"MaxValue":90
},
"SessionElementResponseText":null
}
Code
public static string DataTableToJSON(DataTable table)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> row;
foreach(DataRow dr in table.Rows)
{
row = new Dictionary<string, object>();
foreach(DataColumn col in table.Columns)
{
if(col.ColumnName.Equals("Name"))
{
//Trying here
}
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
serializer.MaxJsonLength = int.MaxValue;
return serializer.Serialize(rows);
}
public static string DataTableToJSON(DataTable table)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
string[] keys = new string[] { "Name", "Value", "Unit", "MinValue", "MaxValue" };
foreach(DataRow dr in table.Rows)
{
Dictionary<string, object> row = new Dictionary<string, object>();
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach(DataColumn col in table.Columns)
{
if(keys.Contains(col.ColumnName)) dict.Add(col.ColumnName, dr[col]);
else row.Add(col.ColumnName, dr[col]);
}
row.Add("VitalThreshold", dict);
rows.Add(row);
}
serializer.MaxJsonLength = int.MaxValue;
return serializer.Serialize(rows);
}
Basically, you have to add one condition to buffer the inner row. Then, at the end of the loop add the "inner row" into the main row.
public static string DataTableToJSON(DataTable table)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> row;
var innerList = new string[] { "Name", "Value", "Unit", "MinValue", "MaxValue" };
var innerRow = new Dictionary<string, object>();
foreach (DataRow dr in table.Rows)
{
row = new Dictionary<string, object>();
foreach (DataColumn col in table.Columns)
{
if (innerList.Contains(col.ColumnName))
{
innerRow.Add(col.ColumnName, dr[col]);
}
else
{
row.Add(col.ColumnName, dr[col]);
}
}
row.Add("VitalThreshold", innerRow);
rows.Add(row);
}
serializer.MaxJsonLength = int.MaxValue;
return serializer.Serialize(rows);
}
LIST Time Status
A 22:05 0
B 22:10 1
C 22:30 1
A 22:40 0
C 22:50 1
B 22:60 1
The above table needs to be converted to below JSON format
[
{ "name": "A",
data: [ [22:05,0],
[22:40,0]
]
},
{ "name": "B",
data: [ [22:10,1],
[22:60,1]
]
}
{ "name": "C",
data: [ [22:30,1],
[22:50,1]
]
}
]
The above is in a DataTable , now need to format the JSON,the below code does not give me in the same format.
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> row = null;
foreach (DataRow dr in dt.Rows)
{
row = new Dictionary<string, object>();
foreach (DataColumn col in dt.Columns)
{
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
I would suggest reading the data from your table and creating a custom class to represent the data that needs to be serialized. You data would be represented in a class that looks like this:
public class MyType {
public string Name {get;set;}
public List<List<string>> Data {get;set;}
}
Then you would need a method to parse through your DataTable. Something like this might do it:
public List<MyType> ParseTable(DataTable dt) {
var myTypes = new List<MyType>();
var dictionary = new Dictionary<string, List<List<string>>>();
foreach(DataRow dr in dt.Rows) {
var name = dr[0];
var time = dr[1];
var status = dr[2];
if(!dictionary.ContainsKey(dr[0]) {
dictionary[name] = new List<List<string>>();
}
dictionary[name].Add(new List<string>{time, status});
}
foreach(var key = dictionary.Keys) {
myTypes.Add(new MyType {Name = key, Data = dictionary[key]});
}
return myTypes;
}
Then use a JSON serializer like http://james.newtonking.com/json to handle the actual serialization of your object into JSON.
That would look something like this:
public string Serialize(List<MyType> myTypes) {
return JsonConvert.SerializeObject(myTypes);
}
Please understand that this is freehand and off the cuff. So it may not be optimal and may need some tweaking. But this should get you where you are trying to go.
I want to convert a DataTable to nested JSON. I have a table Announcement with column name Category, Headline, Details, Short_desc, Author and Display_date.
Datatabel result is like:
Category Headline Details Short_desc Author Display_date
Sports H1 d1 sd1 a1 dd1
Sports h2 d2 sd2 a2 dd2
Technology t1 d3 sd3 a3 dd3
Technology t2 d4 sd4 a4 dd4
Now I want JSON result something like:
{
"Sports" : [ [
"Headline":"H1",
"Details":"d1",
"Short_desc":"sd1",
"Author":"a1",
"Display_date":"dd1"
],
[ "Headline":"H2",
"Details":"d2",
"Short_desc":"sd2",
"Author":"a2",
"Display_date":"dd2"
]
],
"Technology" : [ [
"Headline":"t1",
"Details":"d3",
"Short_desc":"sd3",
"Author":"a3",
"Display_date":"dd3"
],
[ "Headline":"t4",
"Details":"d4",
"Short_desc":"sd4",
"Author":"a4",
"Display_date":"dd4"
]
]
}
I used the following code:
DataTable dts = get_banner_detail_service("");
System.Web.Script.Serialization.JavaScriptSerializer serializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> row;
foreach (DataRow dr in dts.Rows)
{
row = new Dictionary<string, object>();
foreach (DataColumn col in dts.Columns)
{
row.Add(col.ColumnName, dr[col]);
}
rows.Add(row);
}
Response.Write(serializer.Serialize(rows));
Response.Flush();
Response.End();
Result of above code is not like what I expected. It is like:
{
"Sports" : [
"Headline":"H1",
"Details":"d1",
"Short_desc":"sd1",
"Author":"a1",
"Display_date":"dd1"
],
"Sports" :[
"Headline":"H2",
"Details":"d2",
"Short_desc":"sd2",
"Author":"a2",
"Display_date":"dd2"
] ....
}
HI Finally i solve the issue ...
below is the updated code -
DataTable dts = get_banner_detail_service("");
DataTable dtc = get_banner_detail_cat("");
List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();
Dictionary<string, object> rowss;
Dictionary<string, object> rowsc;
List<object> rowsin;
System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
rowsc = new Dictionary<string, object>();
foreach (DataRow dr in dtc.Rows)
{
string cat = dr["Category"].ToString();
var filteredAndroid = (from n in dts.AsEnumerable()
where n.Field<string>("Category").Contains(cat)
select n).ToList();
if (filteredAndroid.Count != 0)
{
DataTable t = filteredAndroid.CopyToDataTable();
t.Columns.Remove("Category");
rowss = new Dictionary<string, object>();
rowsin = new List<object>();
foreach (DataRow drr in t.Rows)
{
foreach (DataColumn col in t.Columns)
{
rowss.Add(col.ColumnName, drr[col]);
}
rowsin.Add(rowss);
rowss = new Dictionary<string, object>();
}
rowsc.Add(cat, rowsin);
t.Dispose();
t = null;
filteredAndroid = null;
}
}
rows.Add(rowsc);
string json = JsonConvert.SerializeObject(rows, Newtonsoft.Json.Formatting.Indented);
if (json.Length > 2)
{
json = json.Substring(1, json.Length - 2);
}
Response.Write(json);
Response.Flush();
Response.End();
You need to create nested dictionary as:
Dictionary<string, Dictionary<string, object>> rows = new Dictionary<string, Dictionary<string, object>>();
Dictionary<string, object> row;
foreach (DataRow dr in dts.Rows)
{
row = new Dictionary<string, object>();
var columns = dts.Columns;
for (int i = 1; i < columns.Count; i++)
{
row.Add(columns[i].ColumnName, dr[columns[i]]);
}
if (rows.ContainsKey(columns[0].ColumnName))
rows[columns[0].ColumnName] = rows[columns[0].ColumnName].Concat(row).ToDictionary(p=>p.Key,v=>v.Value);
else
rows[columns[0].ColumnName] = row;
}