簡體   English   中英

使用 LINQ 返回不同值的平均值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM