Group by an array of objects and select based on multiple conditions - c#

I have an array of objects that may contain duplicate records based on some ID.
I am trying to group the objects by ID and from each group pick the record where either status is 3 or with the earliest date (status takes precedence).
ID Status Last LastModified
1 1 Smith 02/06/2023 04:00 AM
1 2 Smith 02/06/2023 02:00 AM
2 1 Jones 02/01/2023 11:24 AM
3 1 Jack 02/05/2023 02:00 AM
3 3 Jack 02/06/2023 06:00 AM
What I would want from a query is to get the following:
ID Status Last LastModified
1 2 Smith 02/06/2023 02:00 AM
2 1 Jones 02/01/2023 11:24 AM
3 3 Jack 02/06/2023 06:00 AM
I get the records based on date but not sure how to stick the status portion in there:
var filtered = from d in tests.AsEnumerable()
group d by d.ID into g
select g.OrderBy(p => p.DateTime).FirstOrDefault();
This returns:
ID Status Last LastModified
1 2 Smith 02/06/2023 02:00 AM
2 1 Jones 02/01/2023 11:24 AM
3 1 Jack 02/05/2023 02:00 AM

How about:
var filtered =
from d in tests.AsEnumerable()
group d by d.ID into g
select g.OrderByDescending(p => p.Status == 3).ThenBy(p => p.DateTime).FirstOrDefault();

Related

How to calculate count?

I want to calculate the count data from data table dt based on time and I have to store the counts on different variables.
Sample DB :
ID File_Name Uploaded_Time
----- --------- -------------
1 abc 3/18/2015 12:03:26 AM
1 abc 3/18/2015 12:10:26 AM
1 abc 3/18/2015 1:47:26 AM
1 abc 3/18/2015 2:17:52 AM
2 abc 3/18/2015 3:55:26 AM
1 abc 3/18/2015 6:12:44 AM
2 abc 3/18/2015 8:55:26 AM
2 abc 3/18/2015 10:55:26 AM
2 abc 3/18/2015 11:49:26 AM
1 abc 3/18/2015 12:55:26 PM
1 abc 3/18/2015 1:47:26 PM
1 abc 3/18/2015 2:47:26 PM
1 abc 3/18/2015 4:23:15 PM
1 abc 3/18/2015 6:47:26 PM
2 abc 3/18/2015 8:33:45 PM
Code :
protected void btnSubmit_Click(object sender, EventArgs e)
{
CommunicationTableAdapters.tbl_splited_detailsTableAdapter sd;
sd = new CommunicationTableAdapters.tbl_splited_detailsTableAdapter();
DataTable dt = new DataTable();
dt = sd.GetSiteUploadDetails(ddlSiteID.SelectedValue, txtDate.Text);
foreach (DataRow row in dt.Rows)
{
if (dt.Rows.IndexOf(row) != 0)
{
string uplodedtime = (row["Uploaded_Time"].ToString());
}
}
}
Example :
Calculate the count in between 12:00:00 AM to 1:00:00 AM and store in a variable. Like this I want to calculate 24 hrs count and store in 24 variable.
From the above sample DB, the required output is
variable count
-------- -----
hour1 2
hour2 1
hour3 1
hour4 1
hour5 0
hour6 0
hour7 1
hour8 0
hour9 1
hour10 0
hour11 1
hour12 1
hour13 1
hour14 1
hour15 1
hour16 0
hour17 1
hour18 0
hour19 1
hour20 0
hour21 1
hour22 0
hour23 0
hour24 0
This should do it:
var result =
dt.AsEnumerable()
.GroupBy (x => x.Field<DateTime>("Uploaded_Time").Hour)
.Select (x => new { Hour = x.Key, Count = x.Count() });
And if you want to to get a 0 for non existing values use the above expression with:
result = from hour in Enumerable.Range(0, 24)
join item in result on hour equals item.Hour into g
from item in g.DefaultIfEmpty()
select new
{
Hour = hour == 0 ? 24 : hour,
Count = item == null ? 0 : item.Count
};
Since the data is already sorted on the basis of upload time so what you could do is take 5 variables and read each query from the upload time colm.
1st var mon = string till first '/'
2nd var day = string between first '/' and second '/'
3 rd var for year
4th variable for the hour time
and 5 th variable for a look ahead hour time
So in your ques it would be for first query
day = 18
mon = 3
year = 2015
hour_initial = 12
hour_ahead = 12
and increment count till the hour_ahead changes or the day changes.(which ever comes first) and upload count for that specific hour
Then change the hour_intial to next hour and continue the process.....
(this is the basic technique)

Put value in datatable group by month

I have this datatable in c#
Date Employee Job1 Job2 Job3
1/1/2012 a 1 1 1
1/1/2012 b 2 2 2
1/1/2012 c 2 1 4
1/1/2012 d 4 2 1
1/2/2012 a 3 2 5
1/2/2012 b 2 2 2
1/2/2012 c 3 3 3
1/2/2012 d 1 1 1
1/3/2012 a 5 5 5
1/3/2012 b 2 2 6
1/3/2012 c 1 1 1
1/3/2012 d 2 3 4
2/1/2012 a 2 2.5 2
2/1/2012 b 5 5 2
2/1/2012 c 2 2 2
2/2/2012 a 3 3 3
2/2/2012 b 2 3 3
3/1/2012 a 4 4 11
3/5/2012 a 14 42.5 15
3/6/2012 a 21 12.143 22
3/8/2012 a 8.9 45 27
3/8/2012 b 4.4 25 31
I want to loop through the values monthwise such that i can store the value in a datatable and will do the other calculation with that. Here with this example it will have three datatable, first with january values, another one with feb and last one with march rows. How can this be done by Linq. Please suggest the Linq syntax which will group the results month wise.
var monthEmpGroups = dt.AsEnumerable()
.Select(r => new
{
Year = DateTime.Parse(r.Field<string>("DATE")).Year,
Month = DateTime.Parse(r.Field<string>("DATE")).Month.ToString()
})
.GroupBy(x => x.Month);
var dtf = CultureInfo.CurrentCulture.DateTimeFormat;
foreach (var empGroup in monthEmpGroups)
{
int month = int.Parse(empGroup.Key);
string colName = dtf.GetMonthName(month);
// Here i want to get all the rows where month is colName (i.e.january, feb, march)
}
Please suggest if there is other way around to get the values month wise using LINQ.
You should move getting items for every group into monthEmpGroups query:
var monthEmpGroups = (from r in dt.AsEnumerable()
let month = DateTime.Parse(r.Field<string>("DATE")).Month
group r by month into g
select new { Month = g.Key, Items = g.ToList() });
With that you can easily get desired results:
var dtf = System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat;
foreach (var empGroup in monthEmpGroups)
{
int month = empGroup.Month;
string colName = dtf.GetMonthName(month);
List<DataRow> items = empGroup.Items;
}

Line-shift report, Line-day report

I'm generating a line-shift report:
In my application, I'm providing a dropdownlist for selecting shift and line and they will select a date from calender
I have 3 shifts
shift1 starts at 7am and ends at 3pm
shift2 starts at 3pm and ends at 11pm
shift3 starts at 11pm and ends at 3am
I have a table called datalogging where login information will be stored as shown below:
Name Shiftname ID operatorname Date plantname line Machine
Pradeepa Shift2(11-7) 3 Operator 3 2011-05-28 Plant 3 Line5 mc10
Ashwini Shift1(7-3) 1 Operator 1 2011-05-29 Plant 3 Line6 mc12
Deepika Shift2(11-7) 2 Operator 3 2011-05-29 Plant 5 Line9 mc18
Ashwini Shift1(7-3) 1 Operator 1 2011-05-24 Plant 1 Line1 mc1
Deepika Shift2(3-11) 2 Operator 2 2011-05-24 Plant 2 Line3 mc5
Ashwini Shift2(3-11) 1 Operator 2 2011-05-25 Plant 2 Line3 mc5
and so on..
I have a parameter table like temperature,pressure,ph,speed,co2 etc
Temperature table contains following data and this table will contains all the reading from 7am to till 3am
Temperature Time Date
27 13:13:54.000 2011-05-25
27.3 13:14:04.000 2011-05-25
27.6 13:14:14.000 2011-05-25
27.9 13:14:24.000 2011-05-25
28.2 13:14:34.000 2011-05-25
28.5 13:14:44.000 2011-05-25
27 16:13:29.000 2011-05-26
27 16:13:31.000 2011-05-26
and so on..
The user will select a line from dropdownlist and shift and he will select a date from th calender
If the user select shift2,line3 and date 25/05/2011 what are the readings are there between 3pm to 11pm should be displayed in my report
My report should look like:
Machine Shiftname Date Time Temperature
mc5 Shift2 25/05/2011 13:13:54.000 27
mc5 Shift2 25/05/2011 13:14:04.000 27.3
mc5 Shift2 25/05/2011 13:14:14.000 27.6
I'm also doing line-day report
where shiftname should change according to time for eg if time changes to 23:00:00 shiftname should change to shift3 in my report
if the user select particular shift and date for eg if the user selects shift1,line1 and date my report should contain all reading between 7am to 3pm
can any one help me on this.
You could get your report with following query
SELECT d.Machine
, CASE WHEN t.time BETWEEN '19:00:00.000' AND '23:59:59.999' THEN 'Shift1'
WHEN t.time BETWEEN '00:00:00.000' AND '02:59:59.999' THEN 'Shift1'
WHEN t.time BETWEEN '03:00:00.000' AND '10:59:59.999' THEN 'Shift2'
WHEN t.time BETWEEN '11:00:00.000' AND '18:59:59.999' THEN 'Shift3'
END
, t.Date
, t.Time
, t.Temperature
FROM Datalogging d
INNER JOIN Temperature t ON t.Date = d.Date
WHERE d.Shifname = 'Shift2(3-11)'
AND d.Line = 'Line3'
AND t.Date = '25/05/2011'
but if we can assume that each machine would have temperature readings each day, it is clear that there's a relationship missing between your Temperature and Datalogging table.

How select in multitable a single column where the price is greater than "0"?

i have 5 tables how follow below :
City_TBL
CityCode
ABB
DET
FRI
ROM
Hotel_TBL
HotelCode CityCode (FK) Price
1 ABB 0
2 ABB 10
3 FRI 0
4 DET 0
5 ROM 19
HotelRoom_TBL
RoomID HotelCode (FK) RoomName Price
1 1 Superior 3
2 2 DeLuxe 6
3 1 Panoramic 0
4 3 Suite 0
5 4 Presidential 1
Transfer_TBL
TransferCode CityCode (FK) Price
1 ABB 3
2 ABB 6
3 DET 0
4 FRI 0
Cruise_TBL
CruiseCode CityCode (FK) Price
1 ABB 3
2 DET 0
3 FRI 0
4 ROM 0
I want write down a query(linq) which will return a list of CityCode without duplicate record(CityCode) in which has at least a record where the field/Column "Price" (in the Table Hotel_TBL , Transfer_TBL , Cruise_TBL and HotelRoom_TBL) is greater then '0' as follow result as show below :
Result_TBL
ABB
ROM
How i can do it with linq to sql ?
Thanks so much for your attention.
Have a good time.
Cheers
Sorry i modified the question 'cos i forgot to write down another table(HotelRoom_TBL) so please forgive me this mistake .
Thank so much
Perhaps
var data =
ctx.HotelTbl.Where(row => row.Price > 0).Select(row => row.CityCode)
.Union(
ctx.TransferTbl.Where(row => row.Price > 0).Select(row => row.CityCode)
).Union(
ctx.ResultTbl.Where(row => row.Price > 0).Select(row => row.CityCode)
);
Personally I'd be tempted to use ExecuteQuery though:
var data = ctx.ExecuteQuery<string>(#"
select CityCode from Hotel_Tbl where Price > 0
union select CityCode from Transfer_Tbl where Price > 0
union select CityCode from Result_Tbl where Price > 0").ToList();

LINQ Query with grouping and ranking

I have a sql table called predictions with data as below
Week Player Points
201101 Mark 7
201101 Mark 7
201101 Pete 7
201101 Pete 3
201101 Mark 5
201102 Mark 2
201102 Mark 3
201102 Pete 7
201102 Pete 5
201102 Mark 5
201103 Mark 7
201103 Mark 7
201103 Pete 7
201103 Pete 3
201103 Mark 5
Each row in the table represents a football match, hence several per week
The result I need is
Player Count of Weekly wins
Mark 2
Pete 1
So Mark had the most points in week 2011011 and 201103, Pete had the most points in week 201102
Getting the total number of points per player per week is easy. But I cannot work out how to take the highest from that weekly group and get to the result I need.
I have this all in sql query using the RANK function and then selecting all the players who have a rank of 1. This is good because if two players have the same score for a week they both get counted correctly. But I want a LINQ version because it is cool and fits my reworking of a web site!
Any help would be appreciated.
OK I have got this far which is summing the data for each player for each week. What i now need to do is pick the top entry for each week and count it against the player
(from p in FootballPredictions
where p.FootballMatches.WeekNum <= 201101 && p.Points != null
group p by new { p.FootballMatches.WeekNum, p.Player } into g
orderby g.Key.WeekNum, g.Sum(p => p.Points) descending
select new
{
WeekNum = g.Key.WeekNum,
Player = g.Key.Player,
Points = g.Sum(p => p.Points),
})
Giving
WeekNum Player Points
201033 ranteld 26 <--- 1 point
201033 nicolap 25
201033 Mark 25
201033 1969 cup winners 25
201033 footysi 24
201033 Brendan 22
201033 monty 22
201033 Sandra Phillips 21
201033 SPB 20
201033 John Poulton 20
201033 RobBrown 19
201033 Steve Gardner 17
201033 Nick 16
201033 MikeSpeke 15
201034 Sandra Phillips 32 <--- 1 point
201034 Steve Gardner 27
201034 ranteld 25
201034 John Poulton 23
201034 footysi 23
201034 Mark 17
201034 nicolap 13
201034 Brendan 13
201035 Brendan 34 <--- 1 point
201035 Sandra Phillips 34 <--- 1 point
201035 nicolap 31
201035 1969 cup winners 25
201035 MikeSpeke 24
201035 Steve Gardner 22
201035 Mark 20
201035 ranteld 20
201035 Football Freddie 16
So the real answer from this table is
Player Wins
Sandra Philips 2
Brendan 1
ranteld 1
Hope that clarifies
It was somewhat confusing to see that your query didn't seem to correspond to the data. So instead, this will be based on the data alone. The query should produce valid SQL so you won't have to use LINQ to Objects. You can adapt it to your tables with little modification.
var query = from pred in Predictions
group pred.Points by pred.WeekNum into week
join pred in Predictions
on new { WeekNum = week.Key, Points = week.Max() }
equals new { pred.WeekNum, pred.Points }
group 1 by pred.Player into player
let Wins = player.Count()
orderby Wins descending, player.Key
select new
{
Player = player.Key,
Wins,
};
Try:
p.Points.Any()
Instead of:
p.Points != null
This code seems to be what you need:
var result = this.DataList
.GroupBy(data => data.Week)
.Select(data=>
{
return data.GroupBy(item => item.Name)
.Select(item => new { Name = item.Key, SumPoints = item.Sum(v => v.Points) })
.OrderBy(item => item.SumPoints)
.FirstOrDefault();
})
.GroupBy(_=>_.Name)
.ToDictionary(_=>_.Key, _=>_.Count());
mine is quite long
var weeklyTopScore = from eachMatch in FootballPredictions
group eachMatch by eachMatch.week
into weekly
select new {week = weekly.Key, topScore = weekly.Max(match => match.points)};
var playerWins = from eachResult in weeklyTopScore
join entry in FootballPredictions
on eachResult.week equals entry.week
where eachResult.topScore == entry.points
group entry by entry.player
into winner
select new { player = winner.Key, wins = winner.Count() };
var result = from entry in playerWins
group entry by entry.wins
into summary
select new { player = summary.Select(data => data.player).Aggregate((cur, nex) => cur + ", " + nex), wins = summary.Key};
Just pass a datatable to following function (Please note that the code is in c#)
//dt should contain column points but not rank column
public static DataTable GetRankedDatatable(DataTable dt)
{
var rankedDt = (from row in dt.AsEnumerable()
orderby row.Field<string>("points")
select row).CopyToDataTable();
rankedDt.Columns.Add("rank");
int rank = 0;
for (int i = 0; i < rankedDt.Rows.Count - 1; i++)
{
rankedDt.Rows[i]["rank"] = rank;
if (rankedDt.Rows[i]["points"].ToString() != rankedDt.Rows[i + 1]["points"].ToString())
{
rank++;
}
}
rankedDt.Rows[rankedDt.Rows.Count - 1]["rank"] = rank;
return rankedDt;
}

Categories

Resources