C# LINQ Lambda求和空
我使用LINQ to objects对两个对象中的值进行求和,并返回一个包含求和总数的单一版本的对象 我遇到的问题是LINQ sum函数将空值求和为零(0)。如果我有一个值是“15”,另一个值是“null”,那么总和应该是“15”。但我希望,如果第一个值是“null”,第二个值是“null”,那么总和也应该是“null”。然而,它告诉我总和是“0” 我怎样才能让它像我期望的那样工作?如果至少有一个值,我希望它返回一个值;如果没有值,则返回“null” 现在了解一些代码:C# LINQ Lambda求和空,c#,linq,lambda,C#,Linq,Lambda,我使用LINQ to objects对两个对象中的值进行求和,并返回一个包含求和总数的单一版本的对象 我遇到的问题是LINQ sum函数将空值求和为零(0)。如果我有一个值是“15”,另一个值是“null”,那么总和应该是“15”。但我希望,如果第一个值是“null”,第二个值是“null”,那么总和也应该是“null”。然而,它告诉我总和是“0” 我怎样才能让它像我期望的那样工作?如果至少有一个值,我希望它返回一个值;如果没有值,则返回“null” 现在了解一些代码: virtual publ
virtual public IStatSplit Totals
{
get
{
var cSplit = _splits.Where(s => s.Split == SplitType.COMBINED).SingleOrDefault();
if( cSplit != null )
{ return cSplit; }
cSplit = _splits.Where( s => s.Split != SplitType.COMBINED )
.GroupBy( g => 1 == 1 ).Select( x => new StatSplit
{
AB = (uint?)x.Sum( q => q.AB ),
CI = (uint?)x.Sum( q => q.CI ),
B2 = (uint?)x.Sum( q => q.B2 ),
B3 = (uint?)x.Sum( q => q.B3 ),
GDP = (uint?)x.Sum( q => q.GDP ),
H = (uint?)x.Sum( q => q.H ),
HB = (uint?)x.Sum( q => q.HB ),
HR = (uint?)x.Sum( q => q.HR ),
RBI = (uint?)x.Sum( q => q.RBI ),
IBB = (uint?)x.Sum( q => q.IBB ),
SF = (uint?)x.Sum( q => q.SF ),
SH = (uint?)x.Sum( q => q.SH ),
SO = (uint?)x.Sum( q => q.SO ),
BB = (uint?)x.Sum( q => q.BB ),
Split = SplitType.COMBINED
} ).SingleOrDefault();
return cSplit;
}
}
以下是无法通过单元测试的测试数据:
[TestMethod]
public void PitchingTotals()
{
var splits = GetSplits();
var pitching = new Base.Pitching();
pitching.Splits = splits;
var expected = GetTotalSplit();
var result = pitching.Totals;
// result.RBI = 0
// expected.RBI = null
// this fails because the "0" is not expected
Assert.AreEqual( expected, result );
}
private List<IStatSplit> GetSplits()
{
var lhSplit = new Base.StatSplit
{
AB = 442,
H = 97,
B2 = 14,
B3 = 0,
HR = 6,
BB = 28,
HB = 6,
SF = 1,
SH = 5,
SO = 73,
GDP = 7,
IBB = 4,
CI = 0,
RBI = null,
Split = Enumerations.SplitType.VS_LEFT
};
var rhSplit = new Base.StatSplit
{
AB = 633,
H = 101,
B2 = 9,
B3 = 0,
HR = 5,
BB = 34,
HB = 1,
SF = 1,
SH = 10,
SO = 195,
GDP = 11,
IBB = 2,
CI = 0,
RBI = null,
Split = Enumerations.SplitType.VS_RIGHT
};
List<IStatSplit> splits = new List<IStatSplit>();
splits.Add( lhSplit );
splits.Add( rhSplit );
return splits;
}
private IStatSplit GetTotalSplit()
{
var split = new Base.StatSplit
{
AB = 1075,
H = 198,
B2 = 23,
B3 = 0,
HR = 11,
BB = 62,
HB = 7,
SF = 2,
SH = 15,
SO = 268,
GDP = 18,
IBB = 6,
CI = 0,
RBI = null,
Split = Enumerations.SplitType.COMBINED
};
return split;
}
[TestMethod]
公共无效投手总数()
{
var splits=GetSplits();
var pitching=新的基底。pitching();
俯仰。劈裂=劈裂;
应为var=GetTotalSplit();
var结果=俯仰。总计;
//result.RBI=0
//应为0.RBI=null
//此操作失败,因为不需要“0”
断言.AreEqual(预期、结果);
}
私有列表GetSplits()
{
var lhSplit=new Base.StatSplit
{
AB=442,
H=97,
B2=14,
B3=0,
HR=6,
BB=28,
HB=6,
SF=1,
SH=5,
SO=73,
GDP=7,
IBB=4,
CI=0,
RBI=null,
Split=枚举数.SplitType.VS_左
};
var rhSplit=new Base.StatSplit
{
AB=633,
H=101,
B2=9,
B3=0,
HR=5,
BB=34,
HB=1,
SF=1,
SH=10,
SO=195,
GDP=11,
IBB=2,
CI=0,
RBI=null,
Split=Enumerations.SplitType.VS_RIGHT
};
列表拆分=新列表();
拆分。添加(lhSplit);
拆分。添加(rhSplit);
返回分裂;
}
私有IStatSplit GetTotalSplit()
{
var split=new Base.StatSplit
{
AB=1075,
H=198,
B2=23,
B3=0,
HR=11,
BB=62,
HB=7,
SF=2,
SH=15,
SO=268,
GDP=18,
IBB=6,
CI=0,
RBI=null,
Split=枚举数.SplitType.COMBINED
};
收益分割;
}
您应该编写自己的“SumOrNull”扩展方法,在您描述的情况下(null+null=null),该方法可以返回“uint?”。现有的Linq Sum方法只返回不可为空的数字
您可以使用
这将从一个
null
uint?
值开始,并遍历每个项目。如果当前sum
和值currentItem.AB
均为null
,则下一个sum
将继续为null
。如果其中一个不是null
,则添加它们,如果其中一个是null
,则使用默认值,uint
的值为0。根据Juharr的回答,我首先尝试了以下方法:
cSplit = _splits.Where( s => s.Split != SplitType.COMBINED )
.GroupBy( g => 1 == 1 ).Select( x => new StatSplit
{
AB = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.AB.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.AB.GetValueOrDefault() ),
CI = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.CI.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.CI.GetValueOrDefault() ),
B2 = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.B2.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.B2.GetValueOrDefault() ),
B3 = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.B3.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.B3.GetValueOrDefault() ),
GDP = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.GDP.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.GDP.GetValueOrDefault() ),
H = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.H.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.H.GetValueOrDefault() ),
HB = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.HB.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.HB.GetValueOrDefault() ),
HR = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.HR.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.HR.GetValueOrDefault() ),
RBI = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.RBI.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.RBI.GetValueOrDefault() ),
IBB = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.IBB.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.IBB.GetValueOrDefault() ),
SF = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.SF.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.SF.GetValueOrDefault() ),
SH = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.SH.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.SH.GetValueOrDefault() ),
SO = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.SO.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.SO.GetValueOrDefault() ),
BB = x.Aggregate( (uint?)null, ( sum, item ) => !sum.HasValue && !item.BB.HasValue ?
(uint?)null : sum.GetValueOrDefault() + item.BB.GetValueOrDefault() ),
Split = SplitType.COMBINED
} ).SingleOrDefault();
这很管用,但我觉得很难看。我做了一些改进,得出了以下结论:
cSplit = _splits.Aggregate( new StatSplit() { Split = SplitType.COMBINED },
( sum, item ) =>
{
sum.AB = !sum.AB.HasValue && !item.AB.HasValue ? (uint?)null : sum.AB.GetValueOrDefault() + item.AB.GetValueOrDefault();
sum.CI = !sum.CI.HasValue && !item.CI.HasValue ? (uint?)null : sum.CI.GetValueOrDefault() + item.CI.GetValueOrDefault();
sum.B2 = !sum.B2.HasValue && !item.B2.HasValue ? (uint?)null : sum.B2.GetValueOrDefault() + item.B2.GetValueOrDefault();
sum.B3 = !sum.B3.HasValue && !item.B3.HasValue ? (uint?)null : sum.B3.GetValueOrDefault() + item.B3.GetValueOrDefault();
sum.GDP = !sum.GDP.HasValue && !item.GDP.HasValue ? (uint?)null : sum.GDP.GetValueOrDefault() + item.GDP.GetValueOrDefault();
sum.H = !sum.H.HasValue && !item.H.HasValue ? (uint?)null : sum.H.GetValueOrDefault() + item.H.GetValueOrDefault();
sum.HB = !sum.HB.HasValue && !item.HB.HasValue ? (uint?)null : sum.HB.GetValueOrDefault() + item.HB.GetValueOrDefault();
sum.HR = !sum.HR.HasValue && !item.HR.HasValue ? (uint?)null : sum.HR.GetValueOrDefault() + item.HR.GetValueOrDefault();
sum.RBI = !sum.RBI.HasValue && !item.RBI.HasValue ? (uint?)null : sum.RBI.GetValueOrDefault() + item.RBI.GetValueOrDefault();
sum.IBB = !sum.IBB.HasValue && !item.IBB.HasValue ? (uint?)null : sum.IBB.GetValueOrDefault() + item.IBB.GetValueOrDefault();
sum.SF = !sum.SF.HasValue && !item.SF.HasValue ? (uint?)null : sum.SF.GetValueOrDefault() + item.SF.GetValueOrDefault();
sum.SH = !sum.SH.HasValue && !item.SH.HasValue ? (uint?)null : sum.SH.GetValueOrDefault() + item.SH.GetValueOrDefault();
sum.SO = !sum.SO.HasValue && !item.SO.HasValue ? (uint?)null : sum.SO.GetValueOrDefault() + item.SO.GetValueOrDefault();
sum.BB = !sum.BB.HasValue && !item.BB.HasValue ? (uint?)null : sum.BB.GetValueOrDefault() + item.BB.GetValueOrDefault();
return sum;
} );
第一个运行了大约12毫秒,列表中只有两个项目。改进后的第二个在大约9毫秒内运行,列表中只有两项。我选择第二个条目,因为它更高效,看起来更干净,更容易理解。感谢朱哈尔朝着正确的方向努力 事实并非如此。在您引用的同一个链接中,它显示了Sum的大量重载,这些重载将返回可为null的数据类型。它甚至声明,“如果源不包含元素,则此方法返回零。”LOL,它还声明,“结果不包含null值。”我不知道如果返回类型从未打算返回null,为什么返回类型将为null。@ELMOJO我假设它返回null,因为它将为空集合返回null,但在这种情况下它也返回0。我想他们只是想保持返回类型与求和的类型相同。让我试试这个,然后再给你回复。
cSplit = _splits.Aggregate( new StatSplit() { Split = SplitType.COMBINED },
( sum, item ) =>
{
sum.AB = !sum.AB.HasValue && !item.AB.HasValue ? (uint?)null : sum.AB.GetValueOrDefault() + item.AB.GetValueOrDefault();
sum.CI = !sum.CI.HasValue && !item.CI.HasValue ? (uint?)null : sum.CI.GetValueOrDefault() + item.CI.GetValueOrDefault();
sum.B2 = !sum.B2.HasValue && !item.B2.HasValue ? (uint?)null : sum.B2.GetValueOrDefault() + item.B2.GetValueOrDefault();
sum.B3 = !sum.B3.HasValue && !item.B3.HasValue ? (uint?)null : sum.B3.GetValueOrDefault() + item.B3.GetValueOrDefault();
sum.GDP = !sum.GDP.HasValue && !item.GDP.HasValue ? (uint?)null : sum.GDP.GetValueOrDefault() + item.GDP.GetValueOrDefault();
sum.H = !sum.H.HasValue && !item.H.HasValue ? (uint?)null : sum.H.GetValueOrDefault() + item.H.GetValueOrDefault();
sum.HB = !sum.HB.HasValue && !item.HB.HasValue ? (uint?)null : sum.HB.GetValueOrDefault() + item.HB.GetValueOrDefault();
sum.HR = !sum.HR.HasValue && !item.HR.HasValue ? (uint?)null : sum.HR.GetValueOrDefault() + item.HR.GetValueOrDefault();
sum.RBI = !sum.RBI.HasValue && !item.RBI.HasValue ? (uint?)null : sum.RBI.GetValueOrDefault() + item.RBI.GetValueOrDefault();
sum.IBB = !sum.IBB.HasValue && !item.IBB.HasValue ? (uint?)null : sum.IBB.GetValueOrDefault() + item.IBB.GetValueOrDefault();
sum.SF = !sum.SF.HasValue && !item.SF.HasValue ? (uint?)null : sum.SF.GetValueOrDefault() + item.SF.GetValueOrDefault();
sum.SH = !sum.SH.HasValue && !item.SH.HasValue ? (uint?)null : sum.SH.GetValueOrDefault() + item.SH.GetValueOrDefault();
sum.SO = !sum.SO.HasValue && !item.SO.HasValue ? (uint?)null : sum.SO.GetValueOrDefault() + item.SO.GetValueOrDefault();
sum.BB = !sum.BB.HasValue && !item.BB.HasValue ? (uint?)null : sum.BB.GetValueOrDefault() + item.BB.GetValueOrDefault();
return sum;
} );