在特定條件后訂購串列時遇到問題。情況是我為 Range Shooting 構建了一個競賽應用程式,當我要訂購結果串列時,有條件我不知道如何使用 OrderBy() 處理。
這是我使用的類,簡化為僅包含對這個問題很重要的屬性,而 Shot 類在此處顯示沒有意義。我有一個我使用的串列ShooterSignup并嘗試訂購:
射手注冊
public class ShooterSignup
{
public List<Serie> Series { get; set;}
}
意甲
public class Serie
{
public List<Shot> Shots { get; set;}
}
我必須對結果進行排序的條件是:
- 全系列總分
- 中心命中數
這兩個 OrderBy 是直截了當的,沒有問題。但是下一個 OrderBy 步驟是我無法讓它作業的地方。下一步訂購是:
- 上屆意甲最高分
- 僅次于上一個系列的最高分
- 前一項的最高分
- ……
等為數系列拍攝本次比賽。我怎樣才能達到這個順序?甚至可能嗎?
編輯: 這是在對物體框架的查詢中完成的,所以我不能使用在類本身上創建的任何方法,因為物體框架不知道如何將其轉換為存盤程序
uj5u.com熱心網友回復:
讓類定義如下:
public class ShooterSignup
{
public List<Serie> Series { get; set; }
public int GetTotalScore()
{
return Series.Sum(serie => serie.GetScore());
}
public int GetCenterHits()
{
return Series.Sum(serie => serie.GetCenterHits());
}
}
public class Serie
{
public List<Shot> Shots { get; set; }
public int GetScore()
{
return Shots.Sum(shot => shot.Score);
}
public int GetCenterHits()
{
// assume that center hit is a hit with score = 10
return Shots.Count(shot => shot.Score == 10);
}
}
public class Shot
{
public Shot(int score)
{
Score = score;
}
public int Score { get; set; }
}
您可以像這樣定義系列比較器:
Comparer<ShooterSignup> seriesComparer = Comparer<ShooterSignup>.Create((a, b) =>
{
using (var enumeratorA = Enumerable.Reverse(a.Series).GetEnumerator())
using (var enumeratorB = Enumerable.Reverse(b.Series).GetEnumerator())
{
bool moveNextA = enumeratorA.MoveNext();
bool moveNextB = enumeratorB.MoveNext();
while (moveNextA && moveNextB)
{
int scoreA = enumeratorA.Current.GetScore();
int scoreB = enumeratorB.Current.GetScore();
if (scoreA != scoreB)
{
return scoreB - scoreA;
}
moveNextA = enumeratorA.MoveNext();
moveNextB = enumeratorB.MoveNext();
}
if (!moveNextA && !moveNextB)
{
return 0;
}
return moveNextA ? 1 : -1;
}
});
現在您可以對以下串列進行排序ShooterSignup:
var orderedSignups = signups
.OrderBy(s => s.GetTotalScore())
.ThenBy(s => s.GetCenterHits())
.ThenBy(s => s, seriesComparer)
.ToList();
Update. I'm not sure if it is possible to form LINQ to SQL query that returns ShooterSignup list in such an order. The easier way would be to get accumulated totals for each Serie from the database and do ordering on the client side.
You can make server-side query like this:
var seriesTotals = context.Shots
.GroupBy(shot => shot.SerieId)
.Join(context.Series,
g => g.Key,
serie => serie.Id, (grp, serie) => new { grp, serie })
.Join(context.ShooterSignup,
t => t.serie.SignupId, signup => signup.Id,
(t, signup) => new { t, signup })
.OrderByDescending(t => t.t.serie.Id)
.Select(total => new
{
SerieId = total.t.grp.Key,
SignupId = total.signup.Id,
SignupName = total.signup.Name,
SerieScore = total.t.grp.Sum(s => s.Score),
CenterHits = total.t.grp.Count(s => s.Score == 10)
});
The result will be, for example, as follows:
| SerieId | SignupId | SignupName | SerieScore | CenterHits |
|---|---|---|---|---|
| 1 | 1 | A | 99 | 8 |
| 2 | 2 | B | 95 | 6 |
| 3 | 1 | A | 90 | 3 |
| 4 | 2 | B | 94 | 5 |
Now you can group and order series by shooters on the client:
var series = seriesTotals.AsEnumerable()
.GroupBy(s => s.SignupId)
.Select(gr => new
{
gr.FirstOrDefault().SignupName,
TotalScore = gr.Sum(s => s.SerieScore),
CenterHits = gr.Sum(s => s.CenterHits),
Scores = string.Join(",", gr.Select(s => s.SerieScore.ToString().PadLeft(3, '0'))) // aggregate all scores in a single string for each ShooterSignup
})
.OrderByDescending(g => g.TotalScore)
.ThenByDescending(g => g.CenterHits)
.ThenByDescending(g => g.Scores)
.ToList();
This query will produce something like:
| SignupName | TotalScore | CenterHits | Scores |
|---|---|---|---|
| B | 189 | 11 | 094,095 |
| A | 189 | 11 | 090,099 |
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/454026.html
上一篇:如何計算串列B中存在的串列A中每個數字的出現次數,如果不存在則回傳零?
下一篇:Linq選擇查詢的問題
