2014-10-17 61 views
0

我有xml文件来读取和处理数据。我有详细记录列表。我的要求是删除具有相同数字和RefNo但具有正值和负值的记录。处理2列表

方案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(); 

但上面的代码在以下情况下返回零记录。 正面>负面>正面。它应该返回1条记录,取消同一个号码和RefNo的1个正面和1个负面记录。

我想解决方案,在与相同数量和参考号

•正>负>正场景 - 1个记录
•正>负>正>负 - 0记录
•正>负>正>负>正 - 1个记录
•正>负>正>负>正>负 - 0记录
•正>负>正>负>正>ň

假设 负值总是出现在正值之后。我可以通过for循环来做到这一点。但我正在寻找更好的解决方案。 欣赏有人能帮助我。

回答

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> 
+0

感谢杰夫您的帮助 – 2014-10-19 02:01:37

0

我想一个办法可能是GroupByNumberRefNo然后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