【发布时间】:2011-02-18 23:40:27
【问题描述】:
我有一个包含一堆点的列表(带有 X 和 Y 分量)。
我想获取列表中所有点的 Max X,如下所示:
double max = pointList.Max(p=> p.X);
问题是当我在列表中有一个空值而不是一个点时。解决此问题的最佳方法是什么?
【问题讨论】:
我有一个包含一堆点的列表(带有 X 和 Y 分量)。
我想获取列表中所有点的 Max X,如下所示:
double max = pointList.Max(p=> p.X);
问题是当我在列表中有一个空值而不是一个点时。解决此问题的最佳方法是什么?
【问题讨论】:
好吧,你可以过滤掉它们:
pointList.Where(p => p != null).Max(p => p.X)
另一方面,如果您希望 nulls 被视为具有 X 坐标 0(或类似)的点,您可以这样做:
pointList.Max(p => p == null ? 0 : p.X)
请注意,如果序列为空,这两种技术都会抛出异常。一种解决方法(如果需要)是:
pointList.DefaultIfEmpty().Max(p => p == null ? 0 : p.X)
【讨论】:
DefaultIfEmpty。请看我的回答为什么:link
pointList.Max(p => p == null ? (double?)null : p.X)。请注意,对于可空类型 Max 不会抛出异常,即使是空序列也不会。
如果要为空点的 X 提供默认值:
pointList.Max(p => p == null ? 0 : p.X)
或者为空列表提供默认值:
int max = points.Where(p => p != null)
.Select(p => p.X)
.DefaultIfEmpty()
.Max();
【讨论】:
DefaultIfEmpty 应用于 result 类型。
我不建议在这种情况下使用DefaultIfEmpty,因为与其他替代方案相比,它会产生相当大的 SQL。
请看这个例子:
我们有一个页面的模块列表,并希望获得“排序”列的最大值。如果列表没有记录,则返回 null。 DefaultIfEmpty 检查是否为空,当列为空时返回列数据类型的默认值。
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)。
【讨论】:
Convert.ToInt32( (from x in table join y in table 2 on x.ID equals y.ID where y.ProjectID == ProjectID select x.ObservationNum).Max()); 有没有办法使用您的语法进行连接,或者修改我的方法以获取可为空的 int 强制转换?
double max = pointList.Where(p=>p != null).Max(p=>p.X)
应该可以。
【讨论】:
在表达式内部放置一个可为空的强制转换,以确保空白列表将强制转换为空。然后您可以添加默认值。
double max = pointList.Max(p=>(double?)p.X) ?? 0;
【讨论】:
检查 null 对我不起作用。我使用了 DefaultIfEmpty()
int max_sequence = _dbContext.myTable
.Where(e=>e.field1==param.field1
&& e.fieldDate==param.fieldDate
)
.Select(e => e.Sequence)
.DefaultIfEmpty()
.Max();
【讨论】:
【讨论】:
为什么不简单:
double? maxOrNull = pointList.
.Where(p => p != null)
.OrderByDescending(p => p.x)
.FirstOrDefault();
double max = 0;
if (maxOrNull.HasValue) max = maxOrNull.Value;
这可以在内存列表和 Linq2Sql 中使用,而且可能也很有效。
【讨论】:
最大值为空的列如下
var maximum = objectEntity.where(entity => entity.property != null).max(entity => entity.property.HasValue);
以上语句返回实体属性的最大数量
【讨论】: