I have the following datatable :
id name name_in 3 sys sys 5 con con_r 5 con con_s 5 con con_g
I want to get the following datatable from it :
3 sys 5 con
How to do this?
I do the following
var groups = Process_dt.AsEnumerable()
.GroupBy(r => r.Field<Int16>("id"));
but how to put the result in another datatable .
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Have you tried the Distinct() function of LINQ? Code sample:
var groups = (
from DataRow row in Process_dt.AsEnumerable()
select new {
id = row.Field<Int16>("id"),
name = row.Field<string>("name")
}
).Distinct();
Method 2
GroupBy will return you an IGrouping collection which you can iterate the following way:
var dataTable = new DataTable();
dataTable.Columns.Add("id", typeof(Int16));
dataTable.Columns.Add("name_in", typeof(string));
foreach (var group in groups)
{
dataTable.Rows.Add(group.Key, (group.First())["name_in"]);
}
Method 3
You could build your own CopyToDataTable that takes any kind of IEnumerable(not only DataRow)and returns a new DataTable:
var q=from row in Process_dt.AsEnumerable()
group row by (int)row["id"] into IdGroup
select new{id=IdGroup.Key,name=IdGroup.First()["name"]};
// following does not compile by default
// because input is not an IEnumerable<DataRow> but an anonymous type, you need code below
var tblResult = q.CopyToDataTable();
Here is a implementation (with help of MSDN):
public class ObjectShredder<T> {
private System.Reflection.FieldInfo[] _fi;
private System.Reflection.PropertyInfo[] _pi;
private System.Collections.Generic.Dictionary<string, int> _ordinalMap;
private System.Type _type;
// ObjectShredder constructor.
public ObjectShredder() {
_type = typeof(T);
_fi = _type.GetFields();
_pi = _type.GetProperties();
_ordinalMap = new Dictionary<string, int>();
}
/// <summary>
/// Loads a DataTable from a sequence of objects.
/// </summary>
/// <param name="source">The sequence of objects to load into the DataTable.</param>
/// <param name="table">The input table. The schema of the table must match that
/// the type T. If the table is null, a new table is created with a schema
/// created from the public properties and fields of the type T.</param>
/// <param name="options">Specifies how values from the source sequence will be applied to
/// existing rows in the table.</param>
/// <returns>A DataTable created from the source sequence.</returns>
public DataTable Shred(IEnumerable<T> source, DataTable table, LoadOption? options) {
// Load the table from the scalar sequence if T is a primitive type.
if (typeof(T).IsPrimitive) {
return ShredPrimitive(source, table, options);
}
// Create a new table if the input table is null.
if (table == null) {
table = new DataTable(typeof(T).Name);
}
// Initialize the ordinal map and extend the table schema based on type T.
table = ExtendTable(table, typeof(T));
// Enumerate the source sequence and load the object values into rows.
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator()) {
while (e.MoveNext()) {
if (options != null) {
table.LoadDataRow(ShredObject(table, e.Current), (LoadOption)options);
} else {
table.LoadDataRow(ShredObject(table, e.Current), true);
}
}
}
table.EndLoadData();
// Return the table.
return table;
}
public DataTable ShredPrimitive(IEnumerable<T> source, DataTable table, LoadOption? options) {
// Create a new table if the input table is null.
if (table == null) {
table = new DataTable(typeof(T).Name);
}
if (!table.Columns.Contains("Value")) {
table.Columns.Add("Value", typeof(T));
}
// Enumerate the source sequence and load the scalar values into rows.
table.BeginLoadData();
using (IEnumerator<T> e = source.GetEnumerator()) {
Object[] values = new object[table.Columns.Count];
while (e.MoveNext()) {
values[table.Columns["Value"].Ordinal] = e.Current;
if (options != null) {
table.LoadDataRow(values, (LoadOption)options);
} else {
table.LoadDataRow(values, true);
}
}
}
table.EndLoadData();
// Return the table.
return table;
}
public object[] ShredObject(DataTable table, T instance) {
FieldInfo[] fi = _fi;
PropertyInfo[] pi = _pi;
if (instance.GetType() != typeof(T)) {
// If the instance is derived from T, extend the table schema
// and get the properties and fields.
ExtendTable(table, instance.GetType());
fi = instance.GetType().GetFields();
pi = instance.GetType().GetProperties();
}
// Add the property and field values of the instance to an array.
Object[] values = new object[table.Columns.Count];
foreach (FieldInfo f in fi) {
values[_ordinalMap[f.Name]] = f.GetValue(instance);
}
foreach (PropertyInfo p in pi) {
values[_ordinalMap[p.Name]] = p.GetValue(instance, null);
}
// Return the property and field values of the instance.
return values;
}
public DataTable ExtendTable(DataTable table, Type type) {
// Extend the table schema if the input table was null or if the value
// in the sequence is derived from type T.
foreach (FieldInfo f in type.GetFields()) {
if (!_ordinalMap.ContainsKey(f.Name)) {
// Add the field as a column in the table if it doesn't exist
// already.
DataColumn dc = table.Columns.Contains(f.Name) ? table.Columns[f.Name]
: table.Columns.Add(f.Name, f.FieldType);
// Add the field to the ordinal map.
_ordinalMap.Add(f.Name, dc.Ordinal);
}
}
foreach (PropertyInfo p in type.GetProperties()) {
if (!_ordinalMap.ContainsKey(p.Name)) {
// Add the property as a column in the table if it doesn't exist
// already.
DataColumn dc = table.Columns.Contains(p.Name) ? table.Columns[p.Name]
: table.Columns.Add(p.Name, p.PropertyType);
// Add the property to the ordinal map.
_ordinalMap.Add(p.Name, dc.Ordinal);
}
}
// Return the table.
return table;
}
}
Now you can add these extensions:
public static class CustomLINQtoDataSetMethods {
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source) {
return new ObjectShredder<T>().Shred(source, null, null);
}
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source,
DataTable table, LoadOption? options) {
return new ObjectShredder<T>().Shred(source, table, options);
}
}
Voilà! Now CopyToDataTable works with any LINQ query 🙂
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0