我有xml文件来读取和处理数据。我有详细记录清单。我的要求是删除具有相同Number和RefNo但具有正值和负值的记录。
场景1:应返回1条记录
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
场景2:应返回0记录,因为数量为正数且为负数
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-20.0</Amount>
<RefNo>1</RefNo>
</Detail>
我通过使用2个正负值列表来实现它。我使用以下代码解决了上述场景。
var actualRecords =
(from detailList in positiveDetails
where !negativeDetails.Any(x => x.Number == detailList.PolicyNo
&& x.RefNo == detailList. RefNo)
select detailList).ToList();
但是上面的代码在以下场景中返回零记录。 正面&gt;否定&gt;正。对于相同的Number和RefNo,它应该返回1个记录,取消1个正面和1个负面记录。
我想要解决以下具有相同编号和参考号的场景
•正面&gt;否定&gt;正面 - 1记录
•正面&gt;否定&gt;正面&gt;否定 - 0记录
•正面&gt;否定&gt;正面&gt;否定&gt;正面 - 1记录
•正面&gt;否定&gt;正面&gt;否定&gt;正面&gt;否定 - 0记录
•正面&gt;否定&gt;正面&gt;否定&gt;正面&gt; Ñ
假设 负值始终出现在正值之后。我可以通过for循环来做到这一点。但我正在寻找更好的解决方案。 感谢有人可以帮助我。
答案 0 :(得分:0)
我猜一种方法可能是GroupBy
Number
和RefNo
然后Count
正面和负面Amount
如果计数不匹配然后返回那些Detail
元素
类似的东西:
var actualRecords = detailList.GroupBy(x => new{ x.Number, x.RefNo}) // group by Number and RefNo
.Where(x => x.Count(p => p.Amount > 0) // count positives
!= x.Count(n => n.Amount < 0)) // count negatives
.SelectMany(detail => detail); // contains the Details that have unequal amounts of positive and negative amounts
答案 1 :(得分:0)
您是仅仅汇总细节还是实际尝试匹配相互抵消的细节?前者会更容易写。
例如,对于看起来像这样的文档<Root>
<Details>
<Detail>
<Number>1</Number>
<Amount>40.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-30.0</Amount>
<RefNo>2</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
</Details>
</Root>
XDocument doc = ...;
var details = doc.XPathSelectElement("/Root/Details");
var newDetails =
from detail in details.Elements("Detail")
let amount = (decimal)detail.Element("Amount")
let number = (int)detail.Element("Number")
let refNo = (int)detail.Element("RefNo")
// group amounts by number and refno
group amount by new { number, refNo } into g
let amount = g.Sum()
// filter out completely canceled out groups
where amount != 0M
select new XElement("Detail",
new XElement("Number", g.Key.number),
new XElement("Amount", amount.ToString("N1")),
new XElement("RefNo", g.Key.refNo)
);
details.ReplaceAll(newDetails);
收率:
<Root>
<Details>
<Detail>
<Number>1</Number>
<Amount>60.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-30.0</Amount>
<RefNo>2</RefNo>
</Detail>
</Details>
</Root>
否则,您需要匹配相互抵消的元素。它仍然可以在一个查询中完成,但稍微复杂一点。
XDocument doc = ...;
var details = doc.XPathSelectElement("/Root/Details");
var newDetails =
from detail in details.Elements("Detail")
let amount = (decimal)detail.Element("Amount")
let number = (int)detail.Element("Number")
let refNo = (int)detail.Element("RefNo")
let key = Math.Abs(amount) // cancellable amounts
// group amounts by key, number and refno
group amount by new { key, number, refNo } into g
let amount = g.Sum()
// filter out completely canceled out groups
where amount != 0M
let count = (int)Math.Abs(amount / g.Key.key) // how many to recreate
let sign = Math.Sign(amount)
// recreate uncancelled values
from a in Enumerable.Repeat(sign * g.Key.key, count)
select new XElement("Detail",
new XElement("Number", g.Key.number),
new XElement("Amount", a.ToString("N1")),
new XElement("RefNo", g.Key.refNo)
);
details.ReplaceAll(newDetails);
收率:
<Root>
<Details>
<Detail>
<Number>1</Number>
<Amount>40.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>20.0</Amount>
<RefNo>1</RefNo>
</Detail>
<Detail>
<Number>1</Number>
<Amount>-30.0</Amount>
<RefNo>2</RefNo>
</Detail>
</Details>
</Root>