My current output looks like this:
ContestId | Points | Position | Timestamp
1 90 1 2018-06-18 12:00:00
1 80 2 2018-06-18 12:15:00
1 75 3 2018-06-18 12:30:00
1 75 3 2018-06-18 12:25:00
1 72 5 2018-06-18 12:40:00
The tiebreaker is the timestamp.
The data is retrieved from a SQL database using c# MVC. I would like the output to look like:
ContestId | Points | Position | Timestamp
1 90 1 2018-06-18 12:00:00
1 80 2 2018-06-18 12:15:00
1 75 3 2018-06-18 12:25:00
1 75 4 2018-06-18 12:30:00
1 72 5 2018-06-18 12:40:00
This is the Model:
public class ContestResult
{
[Key]
public int Id { get; set; }
public int ContestId { get; set; }
public int Points { get; set; }
public int Position { get; set; }
public DateTime TimeStamp { get; set; }
}
This is the query that generates the output:
pointScores = contestResults.Where(a => a.contestId == contest.id)
.Select((v, i) => new ContestResult
{
ContestId = v.ContestId,
Points = v.Points,
TimeStamp = v.TimeStamp,
Position = db.ContestResults
.Where(a => a.ContestId == contest.id)
.Count(p => p.Points > v.Points) + 1
}).ToList();
How do I iterate through the positions that are tied and re-number the rank position based on the timestamp?
After some researh, I added additional conditions to the Count method.
pointScores = contestResults.Where(a => a.contestId == contest.id)
.Select((v, i) => new ContestResult
{
ContestId = v.ContestId,
Points = v.Points,
TimeStamp = v.TimeStamp,
Position = db.ContestResults
.Where(a => a.ContestId == contest.id)
.Count(p => p.Points > v.Points ||
(p.Points == v.Points && p.TimeStamp < v.TimeStamp)) + 1
}).ToList();
The only issue that I have is that if I add additional fields that I can use to validate a condition, it always evaluates to False, which then does not increment the position value.
Related
I have a data set that looks like below:
Option | Year | Month | Value
-------+------+-------+------
1 | 2011 | 12 | 0
-------+------+-------+------
1 | 2011 | 11 | 1
-------+------+-------+------
2 | 2012 | 6 | 0
-------+------+-------+------
2 | 2012 | 7 | 0
-------+------+-------+------
1 | 2011 | 6 | 2
The result set I am looking for is below :
Option | Year | ChangedCount
-------+------+-------------
1 | 2011 | 3
-------+------+-------------
2 | 2012 | 0
-------+------+-------------
Changed Count represents , if the value has changed in the same year between different months . so say if the value of 06 month was 2 and then 07 it changed to 1 , then changed count will be 1 . If the value for two months remains the same , then changedCount is 0
Here is what I have written so far
var changes = from ord in resultSet
group ord by new
{
ord.Year,
ord.Month,
ord.Option,
ord.Value,
}
into g
select new
{
Year = g.Key.Year,
changed = g.Count(x => x.Value == 0)
+ g.Count(x => x.Value == 1)
+ g.Count(x => x.Value == 2)
};
How do I run comparison for previous value in column ?
{0,1,2} Map ENUM values
This is what I understand from your explanation:
class Record
{
public int Option { get; set; }
public int Year { get; set; }
public int Month { get; set; }
public int Value { get; set; }
}
var resultSet = new List<Record> {
new Record { Option=1, Year=2011, Month=12, Value=0 },
new Record { Option=1, Year=2011, Month=11, Value=1 },
new Record { Option=2, Year=2012, Month=6, Value=0 },
new Record { Option=2, Year=2012, Month=7, Value=0 },
new Record { Option=1, Year=2011, Month=6, Value=2 },
};
Helper Method to count changes:
public static int changeCount(List<Record> Records)
{
int previous = Records[0].Value;
var result_change = 0;
//i used sorted records by month you can do not this if order is not sensitive
foreach (var rec in Records.OrderBy(x=>x.Month))
{
if (rec.Value != previous)
{
result_change++;
}
previous = rec.Value;
}
return result_change;
}
and the actual code :
var changes = resultSet.GroupBy(x => new { x.Year }).Select(g => new
{
Year = g.Key.Year,
changed =changeCount( g.ToList()),
Option = g.First().Option
}).ToList();
Result :
2011,3,1
2012,0,2
Try:
var changes = from ord in resultSet
group ord by new
{
ord.Option,
ord.Year,
}
into g
select new
{
Option = g.Key.Option,
Year = g.Key.Year,
ChangedCount = g.Select(x => x.Value).Sum()
};
OR
resultSet
.GroupBy(x => new { x.Option, x.Year })
.Select(x => new { x.Key.Option, x.Key.Year, ChangedCount = x.Select(x => x.Value).Sum() });
My table is:
id | globalId | taskStatus |
1 | 10 | New |
2 | 11 | New |
3 | 10 | InProgress |
4 | 12 | New |
I would like to have a linq query that returns me result with row 2.
Conditions to check in query
Want to ignore those records which have same globalId and if task status of any record is InProgress. So in this case as record with 1, 3 have same global id 10 but task status of record with id 3 is InProgress, so don't want any of the two records.
Also a check in where condition Id < 4
I have tried the below query
var result = (from meetings in db.Meetings
join taskStatus in db.TaskStatus on meeting.TaskStatusId equals taskStatus.TaskStatusId
where (taskStatus.Name == InternalTaskStatus.New || taskStatus.Name == InternalTaskStatus.ToBePlannedInFuture || taskStatus.Name == InternalTaskStatus.Failed)
&& meeting.CalendarEvent != CalendarEvents.Delete
&& meeting.StartDateTime >= planningPeriodStartDate && meeting.EndDateTime <= planningPeriodEndDate
group meeting by meeting.GlobalAppointmentId into m
select new
{
MeetingResult = m.FirstOrDefault()
}).FirstOrDefault();
In the above query I have added check for task status, want only records with taskStatus-New,Failed,ToBePlannedInFuture. But here I am getting wrong result in this case as per above table I am getting result with id 1.
The ideal way to approach this is to, split the requirement.
Requirement 1 : Ignore Items where id < 4
var step1 = testList.Where(x=>x.id<4);
Requirement 2: Ignore Groups of items with same globalId is same, and none of the elements in group has status in "InProgress"
var step2 = step1.GroupBy(x=>x.globalId)
.Where(x=>!x.Any(c=>c.taskStatus.Equals("InProgress")));
Now you need to flatten the group to get the result as IEnumerabble
var step3= step2.SelectMany(x=>x);
Putting it all together
var result = testList.Where(x=>x.id<4).GroupBy(x=>x.globalId)
.Where(x=>!x.Any(c=>c.taskStatus.Equals("InProgress")))
.SelectMany(x=>x);
public class test
{
public int id { get; set; }
public int globalId { get; set; }
public string taskStatus { get; set; }
}
public void SampleName()
{
List<test> testList = new List<test>()
{
new test() { id = 1, globalId = 10, taskStatus = "New"},
new test() { id = 2 , globalId = 11 , taskStatus = "New"},
new test() { id = 3 , globalId = 10 , taskStatus = "InProgress"},
new test() { id = 4 , globalId = 12 , taskStatus = "New"}
};
var result = testList.Where(q => testList.Count(a => a.globalId == q.globalId) == 1 && q.taskStatus != "InProgress" && q.id < 4).ToList();
}
public class Connector
{
public double Id { get; set; }
public string Name { get; set; }
public double Len { get; set; }
public double Height { get; set; }
public double Count { get; set; }
}
I have a list of such facilities:
List<Connector> resutsList = new List<Connector>();
Below is an example of the contents of such a list:
1 | IZO | 1000 | 200 | 2
2 | IZO | 1000 | 200 | 4
3 | IZO | 600 | 200 | 5
4 | IZO | 1000 | 200 | 2
5 | IZO | 600 | 180 | 7
6 | IZO | 600 | 180 | 3
I need such a result: (This is the sum of the Count positions when the Len and Height conditions are met.)
1 | IZO | 1000 | 200 | 8
2 | IZO | 600 | 200 | 5
3 | IZO | 600 | 180 | 10
Is it possible to do any Linq combination?
Or another simple solution?
Here's my effort.
class Program
{
public class Connector
{
public Connector(double id, string name, double len, double height, double count)
{
Id = id;
Name = name;
Len = len;
Height = height;
Count = count;
}
public double Id { get; set; }
public string Name { get; set; }
public double Len { get; set; }
public double Height { get; set; }
public double Count { get; set; }
}
static void Main(string[] args)
{
var l = new List<Connector>
{
new Connector(1, "IZO", 1000, 200, 2),
new Connector(2, "IZO", 1000, 200, 4),
new Connector(3, "IZO", 600, 200, 5),
new Connector(4, "IZO", 1000, 200, 2),
new Connector(5, "IZO", 600, 180, 7),
new Connector(6, "IZO", 600, 180, 3)
};
var sums = from c in l
group c by new { c.Name, c.Len, c.Height } into g
select new { g.First().Id, g.Key.Name, g.Key.Len, g.Key.Height, Count = g.Sum(x => x.Count) };
}
}
```
Please note that the ids are not exactly like in your example. (1,2,3 vs 1,3,5)
I don't believe you can get the index with query expression syntax, but here is another Linq way to do it and get the desired indexes:
var sums = l.GroupBy(c => new { c.Name, c.Len, c.Height })
.Select((g, index) => new{
Id = index+1,
g.Key.Name,
g.Key.Len,
g.Key.Height,
Count = g.Sum(x => x.Count)
});
Please note the index + 1
What you're trying to do here is group your list by Name, Len & Height, which you can do using the LINQ GroupBy method.
Then, you want to project that group to a new object using Select and a Sum aggregation on the Count property. For example:
var result = list
.GroupBy(x => new { x.Name, x.Len, x.Height })
.Select(x => new { x.Key.Name, x.Key.Len, x.Key.Height, Count = x.Sum(y => y.Count) })
.ToList();
As for the ID - well it makes a limited amount of sense in an aggregate operation. You have basically 2 choices
Use an incrementing number as one of the other answers does
.Select( (x,i) => new { ID = i, ....
That the first ID from the group
.Select(x => new { ID = x.First().ID, ....
you can try is
Here we group the elements of resultList by three conditions Name,Len,Height.Then we create a new Connector object from that group by by using the Len,Height,Name,& Id then we Sum all the elements present in that group and assign Count var with the Sum.
var List = from result in resultList
group d by new { d.Name, d.Len , d.Height} into g
select new Connector
(
Id = g.First().ID,
Name = g.Key.Name,
Len = g.Key.Len,
Height = g.Key.Height,
count = g.Sum(s => s.Count)
);
Note:- this will not generate incrementing ID if you want that you may refer #tymtam's answer
I have a table in SQL Server, I want to calculate the count of records in per day for example, you imagine we have two dates "2017/12/01" to "2018/01/12"
Date New York LA Boston Chicago Cleveland
===================================================================
2017/12/01 10 800 820 245 90
2017/12/02 200 30 120 112 356
2017/12/03 500 44 58 34 321
2017/12/04 120 540 98 67 651
.......
Also city has a code that column name is CityCode for example
new york = 1 , LA = 2 , Boston = 3 , Chicago = 4 , Cleveland = 5
but there is a notice in date column. In fact, my date column is based on string format not the date format. I've written some code, but it has a exception with converting string date to DateTime format.
This code just return results of new York city. Do you think it should repeat this code 5 times for other cities?
public class OrderDateSummary
{
public string Date { get; set; }
public int Total { get; set; }
public int Code { get; set; }
}
var startDate = Convert.ToDateTime(FromDate);
var endDate = Convert.ToDateTime(ToDate);
var newYork = db.tbl_bar
.Where(t => startDate <= DateTime.ParseExact(t.date_rec_slash, "yyyy/MM/dd", null) && DateTime.ParseExact(t.date_rec_slash, "yyyy/MM/dd", null) <= endDate && t.CityCode == 1)
.GroupBy(t => t.date_rec_slash, (date, values) =>
new OrderDateSummary()
{
Date = date,
Total = values.Count(),
})
.OrderBy(summary => summary.Date)
.ToList();
SELECT date::DATE, count(citycode) as total,
CASE
WHEN citycode = 1 THEN 'New York'
WHEN citycode = 2 THEN 'LA'
WHEN citycode = 3 THEN 'Boston'
WHEN citycode = 4 THEN 'Chicago'
WHEN citycode = 5 THEN 'Cleveland'
END
FROM YOUR_TABLE
WHERE date::DATE between '2017/12/01' AND '2017/12/31'
GROUP BY date::DATE, citycode
ORDER BY date desc;
For SQL Server you may have to use
Cast(date as datetime)
instead of
date::DATE.
To use as a stored procedure, do this:
USE YOUR_DATABASE_NAME
GO
CREATE PROCEDURE ANY_PROCEDURE_NAME
AS
now_put_sql_here
GO
Run that and it will create a stored procedure named "ANY_PROCEDURE_NAME" in "YOUR_DATABASE_NAME"
For example, I have the following list of sales personnel, and their scores for two Key Performance Indicators (KPI):
SalesmanID KPI1 KPI2
Alice 20 4
Betty 50 6
Cindy 40 8
Doris 70 2
Emily 30 3
First, we rank the sales personnel based on KPI1 in descending order as follows.
SalesmanID KPI1 KPI1_Rank
Doris 70 1
Betty 50 2
Cindy 40 3
Emily 30 4
Alice 20 5
Next, we rank the sales personnel based on KPI2 in descending order as follows.
SalesmanID KPI2 KPI2_Rank
Cindy 8 1
Betty 6 2
Alice 4 3
Emily 3 4
Doris 2 5
Finally, we put them together to compute the Overall_Rank as the average of KPI1_Rank and KPI2_Rank (i.e. Overall_Score = (KPI1_Rank + KPI2_Rank) / 2)
SalesmanID KPI1_Rank KPI2_Rank Overall_Score
Alice 5 3 4
Betty 2 2 2
Cindy 3 1 2
Doris 1 5 6
Emily 4 4 4
We then proceed to rank the sales personnel according to the Overall_Score in descending order.
SalesmanID Overall_Score Overall_Rank
Doris 6 1
Alice 4 2 (Tie)
Emily 4 2 (Tie)
Cindy 2 4 (Tie)
Betty 2 4 (Tie)
Would this be possible with C# LINQ?
Long code, but it is for educational purposes.
using System.Linq;
namespace ConsoleApplication
{
class Program
{
static void Main (string[] args)
{
var salesmanList = new Salesman[]
{
new Salesman ("Betty", 50, 6),
new Salesman ("Cindy", 40, 8),
new Salesman ("Doris", 70, 2),
new Salesman ("Emily", 30, 3),
};
var rankByKPI1 = salesmanList.OrderByDescending (x => x.KPI1)
.Select ((x, index) => new SalesmanKpiRank (x, index + 1))
.ToArray (); // for debugging only
var rankByKPI2 = salesmanList.OrderByDescending (x => x.KPI2)
.Select ((x, index) => new SalesmanKpiRank (x, index + 1))
.ToArray (); // for debugging only
var overallScoreQuery = from salesman in salesmanList
let kpi1rank = rankByKPI1.Single (x => x.Salesman.Equals (salesman)).Rank
let kpi2rank = rankByKPI2.Single (x => x.Salesman.Equals (salesman)).Rank
select new SalesmanOverallScore (salesman, kpi1rank, kpi2rank);
var rankByOverallScore = overallScoreQuery.OrderByDescending (x => x.Score)
.Select ((x , index) => new { SalesmanOverallScore = x, OverallRank = index + 1});
var result = rankByOverallScore.ToArray ();
}
}
class Salesman
{
public Salesman (string id, int kpi1, int kpi2)
{
ID = id;
KPI1 = kpi1;
KPI2 = kpi2;
}
public string ID { get; }
public int KPI1 { get; }
public int KPI2 { get; }
public override bool Equals (object obj) =>ID == ((Salesman) obj).ID; // put some logic here
public override string ToString () => $"{ID} KPI1 = {KPI1}, KPI2 = {KPI2}";
}
class SalesmanKpiRank
{
public SalesmanKpiRank (Salesman salesman, int rank)
{
Salesman = salesman;
Rank = rank;
}
public Salesman Salesman { get; }
public int Rank { get; }
public override string ToString () => $"{Salesman} KPI Rank = {Rank}"; // kpi1 or kpi2
}
class SalesmanOverallScore
{
public SalesmanOverallScore (Salesman salesman, int kpi1rank, int kpi2rank)
{
Salesman = salesman;
KPI1Rank = kpi1rank;
KPI2Rank = kpi2rank;
}
public Salesman Salesman { get; }
public int KPI1Rank { get; }
public int KPI2Rank { get; }
public double Score => (KPI1Rank + KPI2Rank) / 2d;
public override string ToString () => $"{Salesman.ID} {Score}";
}
}