带 Null 的 LINQ Max()

问题描述 投票:0回答:10

我有一个包含一堆点的列表(带有 X 和 Y 分量)。

我想获取列表中所有点的 Max X,如下所示:

double max = pointList.Max(p=> p.X);

问题是当我在列表中有一个空值而不是一个点时。解决这个问题的最佳方法是什么?

c# linq
10个回答
126
投票

好吧,你可以将它们过滤掉:

pointList.Where(p => p != null).Max(p => p.X)

另一方面,如果您希望

null
被视为具有 X 坐标
0
(或类似)的点,您可以这样做:

pointList.Max(p => p == null ? 0 : p.X)

请注意,如果序列为空,这两种技术都会抛出异常。一种解决方法(如果需要)是:

pointList.DefaultIfEmpty().Max(p => p == null ? 0 : p.X)

30
投票

如果您想为零点的 X 提供默认值:

pointList.Max(p => p == null ? 0 : p.X)

或者为空列表提供默认值:

int max = points.Where(p => p != null)
                .Select(p => p.X)
                .DefaultIfEmpty()
                .Max();

14
投票

在这种情况下,我不建议使用

DefaultIfEmpty
,因为与其他替代方案相比,它会产生相当大的 SQL。

请看这个例子:

我们有一个页面的模块列表,并且想要获取“排序”列的最大值。如果列表没有记录,则返回 null。

DefaultIfEmpty
检查 null 并在列为 null 时返回列数据类型的默认值。

var max = db.PageModules.Where(t => t.PageId == id).Select(t => t.Sort).DefaultIfEmpty().Max();

这会产生以下 SQL:

exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Join1].[A1]) AS [A1]
    FROM ( SELECT 
        CASE WHEN ([Project1].[C1] IS NULL) THEN 0 ELSE [Project1].[Sort] END AS [A1]
        FROM   ( SELECT 1 AS X ) AS [SingleRowTable1]
        LEFT OUTER JOIN  (SELECT 
            [Extent1].[Sort] AS [Sort], 
            cast(1 as tinyint) AS [C1]
            FROM [dbo].[PageModules] AS [Extent1]
            WHERE [Extent1].[PageId] = @p__linq__0 ) AS [Project1] ON 1 = 1
    )  AS [Join1]
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go

如果我们将列转换为可空值并让

Convert.ToInt32()
处理空值,如下所示:

var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Max(t => (int?)t.Sort));

然后我们得到如下SQL:

exec sp_executesql N'SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    MAX([Extent1].[Sort]) AS [A1]
    FROM [dbo].[PageModules] AS [Extent1]
    WHERE [Extent1].[PageId] = @p__linq__0
)  AS [GroupBy1]',N'@p__linq__0 int',@p__linq__0=11
go

我真的推荐使用 ExpressProfiler 来检查执行的 SQL: http://expressprofiler.codeplex.com/

最后一个Linq表达式也可以写成:

var max = Convert.ToInt32(db.PageModules.Where(t => t.PageId == id).Select(t => (int?)t.Sort).Max());

并且会产生相同的 SQL,但我喜欢更简洁的

.Max(t => (int?)t.Sort)


5
投票

在表达式内部放置可为 null 的转换,以确保空白列表将转换为 null。然后您可以添加默认值。

double max = pointList.Max(p=>(double?)p.X) ?? 0;

3
投票
double max = pointList.Where(p=>p != null).Max(p=>p.X)

应该可以。


1
投票

检查 null 对我来说不起作用。我使用了 DefaultIfEmpty()

   int max_sequence = _dbContext.myTable
                .Where(e=>e.field1==param.field1
                && e.fieldDate==param.fieldDate
                )
                .Select(e => e.Sequence)
                .DefaultIfEmpty()
                .Max();

0
投票

尝试强制转换为可为空

double max = (double?)pointList.Max(p => p.X);

更多: 最大还是默认?


0
投票

为什么不简单地:

double? maxOrNull  = pointList.
    .Where(p => p != null)
        .OrderByDescending(p => p.x)
        .FirstOrDefault();
double max = 0;
if (maxOrNull.HasValue) max = maxOrNull.Value;

这将与内存列表和 Linq2Sql 一起使用,并且可能也有效。


0
投票

具有 max 的可为空列如下

var maximum = objectEntity.where(entity => entity.property != null).max(entity => entity.property.HasValue);

以上语句返回实体属性的最大数量


-1
投票

我在这里使用BenchmarkDotNet对一些最常见的推荐方法进行了分析: https://shayhmaor.dev/2024/01/22/a-side-by-side-comparison-of- Three-maximum-linq-aproaches/

这包括

  • 默认为空
  • 按降序排列
  • 以及任何子句的空检查

通过 BenchmarkDotNet,我能够获得平均计算时间以及内存分配。

© www.soinside.com 2019 - 2024. All rights reserved.