[英]Using LINQ to return average of distinct values
我對 LINQ 沒有太多經驗,並且我在使用 LINQ 根據不同列中的不同值提取 ListView 列的平均值、眾數和中位數時遇到了困難。
例如,考慮以下數據:
ReportID TAT Col3 Col4 etc...
-------- --- ---- ---- -------
80424 9 1 7 ...
80424 9 2 3 ...
80424 9 2 2 ...
80423 5 1 5 ...
80425 4 1 5 ...
80423 7 1 4 ...
82541 7 1 5 ...
要提取 TAT(周轉時間)大於 5 天的不同報告的計數,我使用以下內容:
int countDistinctReports = (from ListViewItem itm in lvList.Items
where itm.SubItems[1].Text) > 5
select itm.SubItems[0].Text
).Distinct().Count();
countDistinctReports
值為 3。
為了提取這些報告的最小 TAT,我使用了這個:
string minVal = (from ListViewItem itm in lvList.Items
where itm.SubItems[1].Text) > 5
select itm.SubItems[1].Text
).Min();
minVal
值為 7。
但是,我不知道如何編寫 LINQ 表達式來計算 TAT 大於 5 的不同報告的平均值、眾數和中值 TAT。在上面的示例中,平均值應為 (9+7+7)/3 = 7.67。 模式應該是7。
有人可以幫忙嗎? 非常感謝。
這是重現和解決的問題,僅使用 linq 1-liners:
using System;
using System.Linq;
namespace StackOverflow_StatisticsLinq
{
class Program
{
static void Main(string[] args)
{
var reports = new int[][]
{
new int[] {80424, 9, 1, 7},
new int[] {80424, 9, 2, 3},
new int[] {80424, 9, 2, 2},
new int[] {80423, 5, 1, 5},
new int[] {80425, 4, 1, 5},
new int[] {80423, 7, 1, 4},
new int[] {80541, 7, 1, 5}
};
var reportsTat5Plus = (
from int[] r in reports
where r[1] > 5
orderby r[1] descending
select r)
.GroupBy(r => r[0])
.Select(r => r.First()); // ensure ids are distinct
var average = reportsTat5Plus.Select(r => r[1]).Average();
var mode = reportsTat5Plus.GroupBy(v => v)
.OrderByDescending(g => g.Count())
.First()
.Select(r => r[1])
.First();
var median = reportsTat5Plus.Count() % 2 == 1
? reportsTat5Plus.Skip(reportsTat5Plus.Count() / 2 + 1).Select(r => r[1]).First()
: reportsTat5Plus.Skip(reportsTat5Plus.Count() / 2 - 1).Take(2).Select(r => r[1]).Average();
Console.WriteLine($"Average: {average}");
Console.WriteLine($"mode: {mode}");
Console.WriteLine($"median: {median}");
Console.ReadKey();
}
}
}
對於平均值,還有一個名為Average
的 LINQ 方法。 但是,您必須將字符串轉換為數字才能有效地使用數字算術。
var minVal = (from ListViewItem itm in lvList.Items
where itm.SubItems[1].Text) > 5
select Convert.ToInt32(itm.SubItems[1].Text)
).Average();
然而,中位數或眾數沒有這樣的方法。 你必須創建你自己的。
例如中位數:
string subList = (from ListViewItem itm in lvList.Items
where itm.SubItems[1].Text) > 5
select Convert.ToIn32(itm.SubItems[1].Text)
).OrderBy(x => x).ToList();
var median = subList[subList.Count / 2];
這將首先創建一個包含所有值大於5
項目的列表,然后取中間的項目。
您應該使用 GroupBy 方法。
var groups = myList.GroupBy(e=>e.Key);//here key is your TAT
然后,如果要計算組數:
var count = groups.Count();
如果您想獲得所有組中的最小值:
var mins = groups.Select(g=>g.Min());
如果您想獲取並保留關鍵信息:
var keyedMins = groups.Select(g=>new{K=g.Key,Min=g.Min()};
平均值和其他相同:)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.