How to Group By on Columns in datatable in Linq - asp.net

var res3 = dtPriorityMatrix.AsEnumerable()
.GroupBy(hour => hour.Field<int>("Hour"))
.OrderBy(item => item.Key)
.Select(item => new { Hour = item.Key });
I have a data table with 5 columns and around 200+ rows of data. One has hours (0-23) and others are Priority 1, Priority 2 and so on till Priority 4. I need to extract number of items of each priority for every hour. I need help with the Linq query as it is not my strong field. Thanks

You have to group by both columns. something like this
var query = source.GroupBy(x => new { x.Column1, x.Column2 });
so your code will be
var res3 = dtPriorityMatrix.AsEnumerable()
.GroupBy(hour =>new { hour= hour.Field<int>("Hour"), priority=hour.Field<int>("Priority")} )
.Select(item => new {count=item.count(), Hour = item.Key.hour, priority = item.Key.priority});\
edit
Reply to your comment:
when you have your results in a list, you can write it in anyway that you want.
the out put of the query is a list that contains hour, priority and count.
if you want it in 3 lines of string
string hLine="";
string pLine="";
string countLine="";
foreach(var item in res3)
{
hLine+= item.hour+" ";
pLine+= item.prioriy+" ";
countLine+= item.count+" ";
}
if you want to have them in a table or anything, use the same approach for filling your tables items

Related

Performance server scripting

I have table with multiple customerKey values assigned to a numeric value; I wrote a script where foreach row of data I scan whole table to find all values assigned to the current customerKey and return a highest one;
I have a problem with performance - script processes around 10 records per second - any ideas how to improve this or maybe propose an alternative solution plesae?
function getLastest() {
var date = app.models.magicMain.newQuery();
var date_all = date.run();
date_all.forEach(function(e) { // for every row of date_all
var temp = date_all.filter(function(x) {
return x.SubscriberKey === e.SubscriberKey; // find matching records for the current x.SubscriberKey
});
var dates = [];
temp.forEach(function(z) { // get all matching "dates"
dates.push(z.Date);
});
var finalValue = dates.reduce(function(a, b) { // get highest dates value (integer)
return Math.max(a, b);
});
var record = app.models.TempOperatoins.newRecord(); // save results to DB
record.email = e.SubscriberKey.toString() + " " + finalValue.toString();
app.saveRecords([record]);
});
}
The only suggestion I have would be to add:
var recordstosave = [];
At the top of your function.
Then replace app.saveRecords([record]) with recordstosave.push(record).
Finally outside of your foreach function do app.saveRecords(recordstosave).
I saw major processing time improvements doing this rather than saving each record individually inside a loop.

Crossfilter grouping filtered keys

I have some json, for examle:
data = {
"name":"Bob","age":"20",
"name":"Jo","age":"21",
"name":"Jo","age":"22",
"name":"Nick","age":"23"
}
Next, I use crossfilter, create dimension and filter it:
let ndx = crossfilter(data);
let dim = ndx.dimension(d => d.name).filter(d !== "Jo");
//try to get filtered values
let filtered = dim.top(Infinity); // -> return 2 values where 'name'!='Jo'
//"name":"Bob","age":"20"
//"name":"Nick","age":"23"
let myGroup = dim.group(d => {
if(d === 'Jo') {
//Why we come here? This values must be filtered already
}
})
How can I filter my dimension and don't have these values on 'dim.group'?
Not sure what version you are using, but in the current version of Crossfilter, when a new group is created all records are first added to the group and then filtered records are removed. So the group accessor will be run at least once for all records.
Why do we do this? Because for certain types of grouping logic, it is important for the group to "see" a full picture of all records that are in scope.
It is possible that the group accessor is run over all records (even filtered ones) anyway in order to build the group index, but I don't remember.

How to do a GroupBy statement with ServiceStack OrmLite

I am doing some queries for Data Visualization and rely on GroupBy, Avg, Sum, and similar functions to get a good dataset from the DB.
I would like to use something similar to GroupBy with ServiceStack OrmLite. On the ShippersExample page I see the following query. Is there an easier or better way to do this?
For example, I have a 'location' column and would like to find the top 5 locations of an entry, and list these locations with the amount of times it occurs. I only have 1 table, so no need for joins.
var rows = db.SqlList<ShipperTypeCount>(
"SELECT {0}, COUNT(*) AS Total
FROM Shippers
GROUP BY {0}
ORDER BY Total".Fmt("ShipperTypeId".SqlColumn()));
You can also use a SqlExpression, e.g:
var rows = db.SqlList<ShipperTypeCount>(
db.From<Shipper>()
.GroupBy(x => x.ShipperTypeId)
.OrderBy("Total")
.Select(x => new { x.ShipperTypeId, Total = Sql.As(Sql.Count("*"), "Total") }));
Alternatively instead of using a concrete POCO you can use a generic dictionary to populate a dictionary of ShipperTypeId => Total, e.g:
var q = db.From<Shipper>()
.GroupBy(x => x.ShipperTypeId)
.OrderBy("2")
.Select(x => new { x.ShipperTypeId, Total = Sql.Count("*") });
var results = db.Dictionary<int, int>(q);

How can I set column values to GridView Columns?

I have csv file like this:
I need to show this csv file with gridview. But I must change format like this:
I must select distinct just date and mount columns and use date values on gridview columns.
How can I use values of csv file for Gridview columns?
Assuming that reading the CSV file is not an issue and you have already something like a List<ClassName>, DataTable or List<string[]>. I'm presuming that it's a List<String[]> where the first "column" is Date, the second Mount and the last % in my following approach.
You need real DateTimes and ints to be able to sum percents by date:
var formatProvider = new CultureInfo("de-DE"); // seems to be the correct format
var mountGroups = listOfStringArray
.Select(arr => new
{
Date = DateTime.Parse(arr[0].Trim(), formatProvider).Date,
Mount = arr[1].Trim(),
Percent = int.Parse(arr[2].Trim())
})
.GroupBy(x => x.Mount);
Now you have grouped by Mount, you just need to sum the percents for every day. You can use a DataTable as datasource for the GridView. Here's code that creates the table with the dynamic columns for every day:
var dataSource = new DataTable();
dataSource.Columns.Add("Mount");
var lastWeekColumns = Enumerable.Range(0, 7)
.Select(d => new DataColumn(DateTime.Today.AddDays(-6 + d).ToShortDateString(), typeof(int)))
.ToArray();
dataSource.Columns.AddRange(lastWeekColumns);
Following loop executes the LINQ query and fills the table:
foreach(var grp in mountGroups)
{
DataRow row = dataSource.Rows.Add();
row.SetField("Mount", grp.Key); // because: GroupBy(x => x.Mount);
foreach(DataColumn dayCol in lastWeekColumns)
{
DateTime day = DateTime.Parse(dayCol.ColumnName, formatProvider);
int sumPercent = grp.Where(x => x.Date == day)
.Select(x => x.Percent)
.DefaultIfEmpty(0) // fallback value for missing days
.Sum();
row.SetField(dayCol, sumPercent);
}
}
Now you just need to use it as datasource (AuthoGenerateColumns set to true)
grid.DataSource = dataSource;
grid.DataBind();

List of 10-row DataTables from single query in LINQ to DataTable

I came across this pretty little piece of code here:
List<DataTable> result = DTHead.AsEnumerable()
.GroupBy(row => row.Field<int>("MIVID"))
.Select(g => g.CopyToDataTable())
.ToList();
It creates a List of DataTable's based on the value of a particular field.
Is it possible to tweak this code to instead create a List of DataTables based on the number of records? For example, if I have 18 records, I would want that broken into 2 DataTables with 10 rows each (the last two rows of the second table would be empty). If I have 35 records, I end up with 4 DataTable's, the last 5 rows empty on table 4.
Thanks!
This is like a standard paging mechanism:
var result = DTHead.AsEnumerable();
int pageSize = 10;
int pages = result.Count / pageSize + 1;
for (int i = 0; i < pages; i++)
{
var page = result.Skip(i * pageSize).Take(pageSize).Select (t => t.Name)
.CopyToDataTable();
}
Of course within the loop you'd have to do something meaningful with the page variable.

Resources