我对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.
有人可以帮忙吗?非常感谢。
答案 0 :(得分:2)
这是问题的复制和解决,仅使用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();
}
}
}
答案 1 :(得分:1)
对于平均值,还有一个名为Average
的LINQ方法。但是,您必须将字符串转换为数字才能有效地使用数字算法。
var minVal = (from ListViewItem itm in lvList.Items
where itm.SubItems[1].Text) > 5
select Convert.ToInt32(itm.SubItems[1].Text)
).Average();
然而,中位数或模式没有这样的方法。你必须创建自己的。
E.g。中位数:
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
的所有商品,而不是中心商品。
答案 2 :(得分:0)
您应该使用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()};
平均值和其他值相同:)