代码之家  ›  专栏  ›  技术社区  ›  sander

试图除以零Linq

  •  3
  • sander  · 技术社区  · 8 年前

    我试图根据列的总数和有多少列来计算平均值。

    每部电影都可以有一部电影,我试着把电影数量加起来,然后除以收视率,得到一部电影的平均收视率。

    (reviews.Where(w => w.MovieID == m.MovieID).Sum(o => o.MovieRating)) / reviews.Where(z => z.MovieID == m.MovieID).Count();
    

    但问题是如果计数为0。我能怎么办?

    6 回复  |  直到 8 年前
        1
  •  7
  •   paul    8 年前

    使用内置LINQ怎么样 Average 作用

    reviews
        .Where(z => z.MovieID == m.MovieID)
        .Select(z => z.MovieRating)
        .DefaultIfEmpty(0)
        .Average()
    

    要使查询在服务器上完全运行(我想,这取决于数据库服务器):

    reviews
        .Where(z => z.MovieID == m.MovieID)
        .Average(z => (decimal?)z.MovieRating) ?? 0
    
        2
  •  5
  •   Tim Schmelter    8 年前

    你可以用

    var ratingList = reviews
       .Where(z => z.MovieID == m.MovieID)
       .Select(z => z.MovieRating)
       .ToList();
    if(ratingList.Count > 0)
    {
       double result = ratingList.Sum() / ratingList.Count;
    }
    
        3
  •  1
  •   bommelding    8 年前
    double? score = reviews
       .Where(w => w.MovieID == m.MovieID)
       .Average(w => (double?) w.MovieRating)
       // ?? 0   // optional: pick a default when Average returns null
       ;
    
        4
  •  0
  •   Hasan Gholamali    8 年前

    如果条件如下,只需使用内联:

    var avr = (from a1 in reviews
               where a1.MovieID == m.MovieID
               group a1 by a1.MovieID into g
               select new
               {
                   avr = g.count() == 0 ? 0 : g.sum(r => r.MovieRating) / g.count()
               }).FirstOrDefault().avr;
    
        5
  •  -1
  •   touchofevil    8 年前

    不确定是否特别强调LINQ的使用,但我更愿意将其全部放在for/foreach循环中,而不是多个LINQ。否则下面就行了?

    var matchingReviews = reviews.Where(w => w.MovieID == m.MovieID);
    int matchingReviewCount = matchingReviews.Count();
    if (matchingReviewCount  > 0)
    {
        matchingReviews.Sum(o => o.MovieRating) / matchingReviewCount;
    }
    else
    {
        //return default value?
    }
    
        6
  •  -1
  •   xanatos    8 年前

    我想做一个查询(因为我们可能正在处理一个数据库,每个查询都有一个成本“仅仅因为它是一个查询”),并在SQL端进行所有计算,这样我就可以收到一行(因为如果有1000条评论,我真的不需要下载所有评论…我想要它们的总和 MovieRating 以及他们的计数)。

    // Based on https://stackoverflow.com/a/45144198/613130
    var result = reviews
        .Where(x => x.MovieID == m.MovieID)
        .GroupBy(x => 1)
        .Select(x => ((double?)x.Sum(y => y.MovieRating)) / x.Count())
        .FirstOrDefault() ?? -1.0;
    

    这个 result 将 -1.0 如果没有对 MovieID .注意cast的用法,否则我们可能会有一个整数除法(如果 电影 是一个整数)。

    请注意,如果找不到行,则不会有任何除法(因为不会有除法) Group )

    SQL数据库上的等效查询应为

    SELECT CAST(SUM(x.MovieRating) AS FLOAT) / COUNT(*) 
        FROM Reviews x 
        WHERE x.MovieID = @MovieID 
        GROUP BY 1
    

    但事实上,EF以一种更复杂的方式翻译了它:-)(在EF 6.2.0上测试):

    SELECT 
        CAST( [GroupBy1].[A1] AS float) /  CAST( [GroupBy1].[A2] AS float) AS [C1]
    FROM ( SELECT 
        [Filter1].[K1] AS [K1], 
        SUM([Filter1].[A1]) AS [A1], 
        COUNT([Filter1].[A2]) AS [A2]
        FROM ( SELECT 
            1 AS [K1], 
            [Extent1].[MovieRating] AS [A1], 
            1 AS [A2]
            FROM #Reviews AS [Extent1]
            WHERE [Extent1].[MovieId] = @p__linq__0
        )  AS [Filter1]
        GROUP BY [K1]
    )  AS [GroupBy1]