How to get all DataColumns of a DataTable to Lists - c#

I want to get all DataColumns (of double type) of my DataTable in Lists and then create a Dictionary where the Key would be the header of the DataColumn and the Value would be the List with the data of the DataColumn. How can I achieve this with LINQ?
I tried the following lines without success:
// Create Dictionary
Dictionary<string, List<double>> DataDic = new Dictionary<string, List<double>>();
// Create List
List<double> DataList = new List<double>();
// For each DataColumn save it as a List of double
DataList = (from DataColumn dc in dt.Columns select new double()).ToList();
// Add KVP to DataDic
DataDic.Add(column.ColumnName, DataList);
Thanks in advance.

That is pretty straight forward:
// Create Dictionary
var DataDic = dt.Columns.Cast<DataColumn>()
.Where(dc => dc.DataType == typeof(double))
.ToDictionary(dc => dc.ColumnName,
dc => dt.AsEnumerable()
.Select(r => r.Field<double>(dc.ColumnName))
.ToList()
);

Related

Convert DataTable into a Dictionary using Linq/Lambda

I have a DataTable that I would like to convert into dictionary in C# for my project. I can use the traditional way of programming to achieve the goal but it is not as elegant as using linq/lambda. I tried to use Lambda but I got stuck in how to flatten multiple rows into 1.
I have a mock DataTable for testing purpose.
static DataTable GetData()
{
DataTable table = new DataTable();
table.Columns.Add("Field1", typeof(string));
table.Columns.Add("Field2", typeof(string));
table.Rows.Add("A", "A1");
table.Rows.Add("A", "A2");
table.Rows.Add("B", "B1");
table.Rows.Add("A", "A3");
table.Rows.Add("C", "C1");
table.Rows.Add("D", "D1");
table.Rows.Add("A", "A5");
return table;
}
My traditional way to convert it to Dictionary is:
Dictionary<string, ArrayList> t = new Dictionary<string, ArrayList>();
foreach (DataRow r in GetData().Rows)
{
string k = (string)r["Field1"];
string v = (string)r["Field2"];
if (!t.Keys.Contains(r["Field1"]))
{
t.Add(k, new ArrayList());
}
if (t.Values == null)
{
t[k] = new ArrayList();
}
t[k].Add(v);
}
How do I achieve the same thing with Linq?
I have tried:
var res = GetData()
.AsEnumerable()
.GroupBy(row => row.Field<string>("Field1"))
.Select(grp => grp.First());
This only gives me the first occurrence of the item. I am stuck.
Please help.
Actually, you don't want to convert it to a Dictionary, but to a Lookup. Here's an example:
var lookup = GetData().AsEnumerable()
.ToLookup(r => r.Field<string>("Field1"), r => r.Field<string>("Field2"));
foreach (var grouping in lookup)
{
Console.WriteLine(grouping.Key + ": " + String.Join(", ", grouping));
}
Output:
A: A1, A2, A3, A5
B: B1
C: C1
D: D1
Get Data from Datatable as Dictionary without Linq/Lambda
DataTable dataTable = GetData();
var data = new List<Dictionary<string, object>>();
foreach (DataRow dataTableRow in dataTable.Rows)
{
var dic = new Dictionary<string, object>();
foreach (DataColumn tableColumn in dataTable.Columns)
{
dic.Add(tableColumn.ColumnName, dataTableRow[tableColumn]);
}
data.Add(dic);
}
you can get a Collection:
var res = GetData()
.AsEnumerable()
.Select(grp => new KeyValuePair<string, string>(grp[0].ToString(), grp[1].ToString()));

How to change the data layout of a data table with LINQ

Above is the screen shot of one of my Data Table. I am trying to transform this data into the following format so that I can bind it to one of my grid. I have tried LINQ but unsuccessful.
Could please anyone help me how I can do this. Doesn't necessarily be LINQ but I think it will be easier with LINQ
try below
var result = dataSet.Tables["reportColumns"].AsEnumerable().GroupBy(x => x.Field<string>("Object"))
.Select(g => new
{
ColumnName = g.Key,
DefaultColumn = g.FirstOrDefault(p => p.Field<string>("Attribute") == "DefaultColumn").Field<string>("Value"),
Label = g.FirstOrDefault(p => p.Field<string>("Attribute") == "Label").Field<string>("Value"),
Type = g.FirstOrDefault(p => p.Field<string>("Attribute") == "Type").Field<string>("Value"),
Standard = g.FirstOrDefault().Field<int>("Standard")
}).ToList();
You can use my ToPivotTable extension:
public static DataTable ToPivotTable<T, TColumn, TRow, TData>(
this IEnumerable<T> source,
Func<T, TColumn> columnSelector,
Expression<Func<T, TRow>> rowSelector,
Func<IEnumerable<T>, TData> dataSelector)
{
DataTable table = new DataTable();
var rowName = ((MemberExpression)rowSelector.Body).Member.Name;
table.Columns.Add(new DataColumn(rowName));
var columns = source.Select(columnSelector).Distinct();
foreach (var column in columns)
table.Columns.Add(new DataColumn(column.ToString()));
var rows = source.GroupBy(rowSelector.Compile())
.Select(rowGroup => new
{
Key = rowGroup.Key,
Values = columns.GroupJoin(
rowGroup,
c => c,
r => columnSelector(r),
(c, columnGroup) => dataSelector(columnGroup))
});
foreach (var row in rows)
{
var dataRow = table.NewRow();
var items = row.Values.Cast<object>().ToList();
items.Insert(0, row.Key);
dataRow.ItemArray = items.ToArray();
table.Rows.Add(dataRow);
}
return table;
}
Create strongly-typed data from your source table:
var data = from r in table.AsEnumerable()
select new {
Object = r.Field<string>("Object"),
Attribute = r.Field<string>("Attribute"),
Value = r.Field<object>("Value")
};
And convert them to pivot table:
var pivotTable = data.ToPivotTable(r => r.Attribute,
r => r.Object,
rows => rows.First().Value);
This will create pivot table with distinct values of Attribute (i.e. DefaultColumn, Label, Type) as columns, rows will be groups for each Object value, and each cell will have value of corresponding Value property for object group and attribute column.
Or in single query:
var pivotTable = table.AsEnumerable()
.Select(r => new {
Object = r.Field<string>("Object"),
Attribute = r.Field<string>("Attribute"),
Value = r.Field<object>("Value")
})
.ToPivotTable(r => r.Attribute,
r => r.Object,
rows => rows.First().Value);

DataTable Select Expression

I want to select those gesellschaft_id's who have duplicates. I used the code below. this is selecting distinct gesellschaft_id. How to write the select expression to select that row, which rows, gesellschaft_id have more values in the datatable?
foreach (DataRow dr1 in table1.Rows)
{
DataRow[] drDup = table2.Select("('" + dr1[0].ToString() + "' = gesellschaft_id ) AND Count(gesellschaft_id)>1");
}
This will give you the DataRows which have a gesellschaft_id which exists in more than one row:
var rowsWithADuplicateGesellschaftId = table1.Rows
.Cast<DataRow>()
.GroupBy(row => row["gesellschaft_id"])
.Where(group => group.Count() > 1)
.ToArray();
public ArrayList FindDuplicateRows(DataTable dTable, string colName)
{
Hashtable hTable = new Hashtable();
ArrayList duplicateList = new ArrayList();
//add duplicate item value in arraylist.
foreach (DataRow drow in dTable.Rows)
{
if (hTable.Contains(drow[colName]))
duplicateList.Add(drow);
else
hTable.Add(drow[colName], string.Empty);
}
return duplicateList;
}
Also useful duplicate find and add/remove links:
http://www.dotnetspider.com/resources/4535-Remove-duplicate-records-from-table.aspx
http://www.dotnetspark.com/kb/94-remove-duplicate-rows-value-from-datatable.aspx
You could do something like this, assuming that the first column is the one which you want to check for duplicates. This of course assumes that you have Linq available.
var duplicateIds = table2.AsEnumerable()
.GroupBy(row = row[0])
.Where(x => x.Count() > 1);
If you add a bit more detail to the question, that would be helpful.

C# looping through List<dictionary<string,string>> to populate a DataTable

I need to loop through a List of Dictionaries
List<Dictionary<string,string>>
to populate a DataTable. Each Dictionary in the list has a Key, which needs to be the column name, and a Value which is what's in that column. The list contains 225 dictionaries (225 rows to the table).
List<Dictionary<string, string>> myList =
JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jsonRep);
DataTable dt = new DataTable();
//loop through list, loop through dictionaries, add keys as columns,
//values as rows.
so far, I have been trying..
//get max columns
int columns = myList[0].Count; <--gives me 13
//add columns
for (int i = 0; i < columns; i++)
dt.Columns.Add(string myList[i].Keys); <--somehow get to the key in dict to add as column names
//add rows
foreach (var x in myList)
{
dt.Rows.Add(x); <--not working
}
jsonReprValue = dt; <--save new DataTable to var jsonReprValue
How do I do this correctly?
Thanks!
You have two problems. One is adding the columns, and the other is adding the rows.
Adding the columns
Assuming your list has items in it, and that all the dictionaries in the list have the same keys, then you only need to add columns from one of the dictionaries:
foreach(string column in myList[0].Keys)
{
dt.Columns.Add(column);
}
Adding the Rows
Change this:
foreach (var x in myList)
{
dt.Rows.Add(x); <--not working
}
To this:
foreach(Dictionary<string, string> dictionary in myList)
{
DataRow dataRow = dt.NewRow();
foreach(string column in dictionary.Keys)
{
dataRow[column] = dictionary[column];
}
dt.Rows.Add(dataRow);
}
See DataTable.NewRow.
Reiview DataTable Class's example on how to work with a data table. But here is an example using Linq
List<Dictionary<string, string>> myList = new List<Dictionary<string, string>>()
{ new Dictionary<string,string>() { { "ABC", "This" },
{ "DEF", "is" },
{ "GHI", "radio" },
{ "JKL", "clash" } } };
DataTable dt = new DataTable();
// Add columns first
dt.Columns.AddRange( myList.First ()
.Select (kvp => new DataColumn() { ColumnName = kvp.Key, DataType = System.Type.GetType("System.String")} )
.AsEnumerable()
.ToArray()
);
// Now add the rows
myList.SelectMany (Dict => Dict.Select (kvp => new {
Row = dt.NewRow(),
Kvp = kvp
}))
.ToList()
.ForEach( rowItem => {
rowItem.Row[rowItem.Kvp.Key] = rowItem.Kvp.Value;
dt.Rows.Add( rowItem.Row );
}
);
dt.Dump();
The result (Dump is LinqPad specific not .Net):

Winform, ListBox datasource to Dictionary<string, string> conversion?

In winform application, binding the Listbox with Dictionary via BindingSource property.
How do I get this BindingSource back to original Dictionary by type casting?
Eg:
Dictionary<string, string> objDic = getData();
OrderedDictionry ord = GetOrderedDict(objDic)
listBox.DataSource = new BindingSource(ord , null);
listBox.DisplayMember = "Value";
listBox.ValueMember = "Key";
Now, I want same Dictionary type value from listBox.DataSource for Linq query!!.
Eg:
var r = from t in (listBox.DataSource as Dictionary<string, string>).AsEnumaerable()
select t;
throws error?
How to type cast to dictionary ?
You're trying to cast a BindingSource to a Dictionary. You need to cast the BindingSource's DataSource.
I don't think you can cast from OrderedDictionary to Dictionary<>, but it would be easy to just reconstruct the Dictionary<string, string>:
BindingSource bs = (BindingSource)listBox1.DataSource;
OrderedDictionary ord = (OrderedDictionary)bs.DataSource;
Dictionary<string, string> dict = new Dictionary<string, string>();
foreach (DictionaryEntry item in ord)
dict.Add(item.Key.ToString(), item.Value.ToString());
If you want a LINQ version, you could do:
BindingSource bs = (BindingSource)listBox1.DataSource;
OrderedDictionary ord = (OrderedDictionary)bs.DataSource;
var dict = ord.Cast<DictionaryEntry>().ToDictionary(d => d.Key, d => d.Value);
EDIT 2 - after further discussion/checks:
Dictionary<string, string> A = (from t in ((OrderedDictionary)(((BindingSource)listBox1.DataSource).DataSource)).Cast<KeyValuePair<string, string>>() select t).ToDictionary(d => d.Key, d => d.Value);

Categories

Resources