我正在使用LINQ to对象来对两个对象中的值求和,并返回该对象的单个版本以及总和。
我遇到的问题是LINQ求和函数将NULL求和为零(0)。我希望如果我有一个值'#34; 15"而另一个值为" null",总和应为" 15"。但我希望如果第一个值是" null"第二个值是" null",总和也应该是" null"。但是,它告诉我,总和是" 0"。
我怎样才能让它像我期望的那样发挥作用?如果至少有一个值或返回" null"我希望它通过返回一个值来表现。如果没有价值观。
现在有些代码:
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;
}
答案 0 :(得分:2)
您可以使用Aggregate
Sum
x.Aggregate(
(uint?)null,
(sum, currentItem) =>
!sum.HasValue && !currentItem.AB.HasValue ?
(uint?)null :
sum.GetValueOrDefault() + currentItem.AB.GetValueOrDefault());
这将以null
uint?
值开头,并遍历每个项目。如果当前sum
和值currentItem.AB
都是null
,那么下一个sum
将继续为null
。如果其中任何一个不是null
,则会添加它们,如果null
为uint
,则使用默认值,{{1}}为0。
答案 1 :(得分:0)
你应该写自己的&#34; SumOrNull&#34;可以返回&#34; uint的扩展方法?&#34;在你描述的情况下(null + null = null)。现有的Linq Sum方法只返回一个不可为空的数字。
答案 2 :(得分: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毫秒内运行,列表中只有两个项目。我将使用第二个条目,因为它更高效,也看起来更干净,更容易遵循。感谢Juharr推动正确的方向!