LINQ extract dataTable information - c#

I have a DataTable with these 2 columns of intereset:
Category Sum
cat1 10
cat1 15
cat2 20
cat2 25
cat3 30
cat3 35
I want to find with LINQ each first row that has a different category than “cat1” and extract the category name and sum.
So to have as output “cat2”-20 and “cat3”-30. This output can be of any kind, dictionary,dataTable,etc.
This could be split into LINQ queries, 1 to find all the different categories and 1 to find the sum.
Can you help ?

Using LINQ (Main DataTable to another DataTable which is your Extracted data)
DataTable extractedDT = new DataTable();
DataRow dtr;
extractedDT.Columns.Add("Category");
extractedDT.Columns.Add("Sum");
yourMainDataTableCollection.AsEnumerable()
.Where(w => w.Field<string>("Category") != "Cat1")
.ToList()
.ForEach(f =>
{
dtr = extractedDT.NewRow();
dtr["Category"] = f.ItemArray[0];
dtr["sum"] = f.ItemArray[1];
extractedDT.Rows.Add(dtr);
});
extractedDT is your collection output.

Related

Can LINQ be used to extract rows from a DataTable that meet a specified column value

I am writing a C# application that needs to extract rows from a DataTable that contain a specific value in one of the columns.
Example data would be like;
ID Value1 Value2
-----------------------
1 AAA BBB
2 MMM CCC
1 RRR 999
2 ZZZ XXX
I want to extract rows for ID = 1 and then ID = 2 into separate new DataTables. Is there anything in LINQ that can accomplish this? I will also have the situation where I will have two columns that are key values for rows.
A very easy Method :)
List<DataTable> Tables = new List<DataTable>();
//Have some loop to search each item
IEnumerable<DataRow> query = from MyRows in Olddt.AsEnumerable()
where MyRows.Field<int>("ID") == ItemToSearch ||
MyRows.Field<string>("Value1").Contains(ItemToSearch ) ||
MyRows.Field<string>("Value2").Contains(ItemToSearch )
select MyRows;
DataTable dtNew = query.CopyToDataTable();
Tables.Add(ss); // Add New Datatable to Collection of DataTables.

using distinct in DataTable.Select function

I have a data table and I want to populate two extra datatables using this datatable,here is a simple form of my table
My data table columns are
[name][family][id][propertyid][propertyEnergy]
John smith 1 12 Gas
John smith 1 13 Gas
John smith 1 14 null
John smith 1 15 Gas
Hannah smith 2 16 Gas
Hannah smith 2 17 Gas
Hannah smith 2 18 Gas
I want to use this query in datatable select distinct [name][family][id] from table
which results
John smith 1
Hannah smith 2
and again I use this query in another datatable select [id][propertyid][propertyEnergy] from table which results
1 12 Gas
1 13 Gas
1 14 null
1 15 Gas
2 16 Gas
2 17 Gas
2 18 Gas
I searched and found that I can DataTable.Select but examples that I have seen shows that I can only add Where sentense to DataTable.Select and I have no idea how to perform things like Distinct in it,
Can you please help me or give me some hints how to do it?
Thank you so much
I'd use Linq-To-DataTable instead:
var distinctNames = table.AsEnumerable()
.Select(row => new
{
Name = row.Field<string>("Name"),
Family = row.Field<string>("Family"),
ID = row.Field<int>("ID")
})
.Distinct();
var distinctProperties = table.AsEnumerable()
.Select(row => new
{
ID = row.Field<int>("ID"),
PropertyID = row.Field<int>("PropertyID"),
PropertyEnergy = row.Field<int>("PropertyEnergy")
})
.Distinct();
If you need two additional DataTables you have to create and fill them manually since the columns are different than the main-table. You can fill them in a loop from the queries above.
This should work as it is:
string[] nameColumns = { "Name", "Family", "ID" };
DataTable tblNames = table.Clone();
var removeColumns = tblNames.Columns.Cast<DataColumn>()
.Where(c => !nameColumns.Contains(c.ColumnName)).ToList();
removeColumns.ForEach(c => tblNames.Columns.Remove(c));
foreach (var x in distinctNames)
tblNames.Rows.Add(x.Name, x.Family, x.ID);
string[] propertyColumns = { "ID", "PropertyID", "PropertyEnergy" };
DataTable tblProperties = table.Clone();
removeColumns = tblProperties.Columns.Cast<DataColumn>()
.Where(c => !propertyColumns.Contains(c.ColumnName)).ToList();
removeColumns.ForEach(c => tblProperties.Columns.Remove(c));
foreach (var x in distinctProperties)
tblProperties.Rows.Add(x.ID, x.PropertyID, x.PropertyEnergy);

How to achieve Count(Distinct {x}) from dataTable using c#?

I want to find out the count of the distinct values of a particular column of a DataTable and store the result in listbox.
Currently, I have the code to extract the distinct values of a column of a DataTable and store it in a ListBox as follows:-
var ids = dt.AsEnumerable()
.Select(s => new
{
EventID = s.Field<Int32>("ID"),
})
.Distinct().ToList();
listBox.DataSource = ids;
where dt is the name of the DataTable
ID is the name of the column
For Eg:-
Table is
Name ID Marks
Ashish 10 200
Ram 100 300
Sur 200 800
Shim 10 899
Kam 100 989
Then the result in the listbox should appear as:-
{ID=10}{Count=2}
{ID=100}{Count=2}
{ID=200}{Count=1}
Currently I am getting output as:-
{ID=10}
{ID=100}
{ID=200}
Please help!!
You can use GroupBy:
var idCounts = dt.AsEnumerable()
.GroupBy(row => row.Field<int>("ID"))
.Select(g => new
{
EventID = g.Key,
Count = g.Count()
})
.ToList();
listBox.DataSource = idCounts;

Linq query to sum by group

I have a data table like this:
Category Description CurrentHours CTDHours
LC1 Cat One 5 0
LC2 Cat Two 6 0
LC3 Cat Three 18 0
LC1 Cat One 0 9
LC2 Cat Two 0 15
LC4 Cat Four 0 21
That I need to Group and Sum to this:
Category Description CurrentHours CTDHours
LC1 Cat One 5 14
LC2 Cat Two 6 21
LC3 Cat Three 18 0
LC4 Cat Four 0 21
In other words I need to sum the two Hours columns grouping by the Category and Description columns.
I know that I could build a new table and loop through the existing data and sum the data into the new table but I thought there would be an easier way to do it using Linq. I've googled it for a few hours but all the examples I found didn't seem to fit what I was trying to do.
BTW, the odbc driver that creates the data table does not have the capability for sub queries, etc. or I would have just done it using SQL.
Use anonymous object to group by category and description. Here is Linq to DataSet query which returns grouped hours:
from r in table.AsEnumerable()
group r by new {
Category = r.Field<string>("Category"),
Description = r.Field<string>("Description")
} into g
select new {
Category = g.Key.Category,
Description = g.Key.Description,
CurrentHours = g.Sum(x => x.Field<int>("CurrentHours"),
CTDHours = g.Sum(x => x.Field<int>("CurrentHours") + x.Field<int>("CTDHours"))
}
If you are querying database (not clear from question):
from r in context.Table
group r by new {
r.Category,
r.Description
} into g
select new {
g.Key.Category,
g.Key.Description,
CurrentHours = g.Sum(x => x.CurrentHours),
CTDHours = g.Sum(x => x.CTDHours + x.CurrentHours)
}
You need to sum CurrentHours and CTDhours, so -
select new {
...
CTDHours = g.Sum(x => x.Field<int>("CTDHours") + g.Sum(x => x.Field<int>("CurrentHours")
}

Populating an ObservableCollection of ObservableCollection, delimited by two database columns

My database is as follows :
ID Date Number NumberIWishToRecord
What I wish to do is use a Linq-to-SQL query to populate an ObservableCollection<ObservableCollection<CustomClass>>.
What I want is select only the rows were Number == a given parameter.
ID refers to a person, what I want to do is get all the information about a person and store it in an ObservableCollection, so I will have an ObservableCollection<CustomClass>, with each CustomClass holding information about only one row, and each ObservableCollection<CustomClass> holding information about only one person (recorded on different days).
I then wish to select an ObservableCollection of the ObservableCollection<CustomClass> which will hold information on all people!
So, some sample data :
ID Date Number NumberIWishToRecord
1 27-06-2012 0.1933 25
1 28-06-2012 0.1933 27
1 29-06-2012 0.1933 29
2 14-06-2012 0.1933 412
2 15-06-2012 0.1741 321
So when I run my method, I want to return only the Numbers of the given parameter, in my case I will choose 0.1933.
I then want both rows where ID = 1 to be saved in an ObservableCollection<CustomClass>, and the single row where ID == 2 to be saved in another ObservableCollection<CustomClass>. Then, both of these ObservableCollections will be held in their own ObservableCollection! To illustrate :
ObservableCollection<ObservableCollection<CustomClass>>
ObservableCollection<CustomClass>
1 27-06-2012 0.1933 25
1 28-06-2012 0.1933 27
1 29-06-2012 0.1933 29
ObservableCollection<CustomClass>
2 14-06-2012 0.1933 412
How would I write a query in linq to sql that would do this ?
I'll just write a standard query syntax Linq expression to achieve this, you adapt it for your tables.
var rowsById = new ObservableCollection<ObservableCollection<row>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<row>(rowIdGroup));
If you need to convert data from the row into the CustomClass:
var rowsById = new ObservableCollection<ObservableCollection<CustomClass>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<CustomClass>(
rowIdGroup.Select(r => new CustomClass
{
ID = r.ID,
Number = r.number // add more
})));
Or if you prefer query syntax in all the expression:
var rowsById = new ObservableCollection<ObservableCollection<CustomClass>>(
from r in _rows
where r.number == 1.2
group r by r.ID into rowIdGroup
select new ObservableCollection<CustomClass>(
from gr in rowIdGroup select new CustomClass
{
ID = gr.ID,
Number = gr.number
}));

Categories