2014-10-17 77 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