合并3个包含对其他对象的引用的对象列表

时间:2017-04-28 15:59:12

标签: c# linq

我有以下两种类型的两个列表(两者都是更复杂类型的紧凑版本):

class Person
{
    public Guid ID {get; set;}
    public Account PrivateAccount { get; set; }
    public Account SharedAccount { get; set; }
}

class Account
{
    public Guid AccountId {get; set;}
    public decimal Amount { get; set; }
}

我还创建了以下类型:

class PersonWithAmounts
{
    public Guid PersonID {get; set;}
    public decimal PAmount { get; set; }
    public decimal SAmount { get; set; }  
} 

保存4种查询的结果:

  1. PersonPrivateAccount且无SharedAccount

  2. Person没有PrivateAccountSharedAccount

  3. Person同时包含PrivateAccountSharedAccount

  4. Person s没有PrivateAccount且没有SharedAccount

  5. 以下是查询:

    var PAccount = (from person in PersonList
                        where person.PrivateAccount != null
                        join account in accountList on person.PrivateAccount.AccountId equals account.AccountId
                        select new PersonWithAmounts { PersonID = person.ID, PAmount = account.Amount })
                        .ToList();
    
    var SAccount = (from person in PersonList
                         where person.SharedAccount != null
                         join account in accountList on person.SharedAccount.AccountId equals account.AccountId
                         select new PersonWithAmounts {PersonID = person.ID, SAmount = account.Amount })
                        .ToList();
    
    var noAccount = (from person in PersonList
                     where person.PrivateAccount == null && person.SharedAccount == null
                     select new PersonWithAmounts { PersonID = person.ID })
                     .ToList();
    

    我有一种感觉,我将它们合并到一个列表中的操作很复杂,并且不需要,并且想知道如何使它更具可读性(并且可能更高效):

    var resultGroup = PAccount
                      .Concat(SAccount)
                      .Concat(noAccount)
                      .GroupBy(p => p.PersonID)
                      .Select(p => new PersonWithAmounts
                       {
                           PersonID = p.Key,
                           PAmount = p.Select(a => a.PAmount).ElementAt(0),
                           SAmount = p.Select(a => a.SAmount).Count() > 1 ? 
                                     p.Select(a => a.SAmount).ElementAt(1) : 
                                     p.Select(a => a.SAmount).ElementAt(0)
                       })
                      .ToList();
    

    Example program

    注意:给出了3个列表,我必须使用它们(对于任何想知道原因的人,我使用的是Dynamics CRM及其LINQ提供程序,不能使用作为常规的,所以我需要坚持非常简单的查询。)

    澄清

    1. 如上所述,PersonWithAmounts是由我创建的类,因此它不是强制性的。
    2. 我说我正在做“4个查询”,但实际上我需要最终得到4种不同类型的Person。最后的查询(resultGroup)实现了它,但是作为评论,我对GroupBy的结果顺序做了一个有问题的假设。
    3. resultGroup的结果应包括PersonList(上述4种类型)的所有记录。我认为链接的例子证明了这一点。
    4. 请运行以下内容 - 这是我输入和输入的表示。期望的输出(取自LinqPad):
    5. <!DOCTYPE HTML []>
      <html>
        <head>
          <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
      	<meta http-equiv="X-UA-Compatible" content="IE=edge" />
          <meta name="Generator" content="LINQ to XML, baby!" />
          <style type="text/css">
      body {
      	margin: 0.3em 0.3em 0.4em 0.4em;
      	font-family: Verdana;
      	font-size: 80%;
      	background: white
      }
      
      p, pre {
      	margin:0;
      	padding:0;
      	font-family: Verdana;
      }
      
      table {
      	border-collapse: collapse;
      	border: 2px solid #17b;
      	margin: 0.3em 0.2em;
      }
      
      table.limit {
      	border-bottom-color: #c31;
      }
      
      table.expandable {
      	border-bottom-style: dashed;
      }
      
      table.error {
      	border-bottom-width: 4px;
      }
      
      td, th {
      	vertical-align: top;
      	border: 1px solid #aaa;
      	padding: 0.1em 0.2em;
      	margin: 0;
      }
      
      th {
      	text-align: left;
      	background-color: #ddd;
      	border: 1px solid #777;
      	font-family: tahoma;
      	font-size:90%;
      	font-weight: bold;
      }
      
      th.member {
      	padding: 0.1em 0.2em 0.1em 0.2em;
      }
      
      td.typeheader {
      	font-family: tahoma;
      	font-size: 100%;
      	font-weight: bold;
      	background-color: #17b;
      	color: white;
      	padding: 0 0.2em 0.15em 0.1em;
      }
      
      td.n { text-align: right }
      
      a:link.typeheader, a:visited.typeheader, a:link.extenser, a:visited.extenser, a:link.fixedextenser, a:visited.fixedextenser {
      	font-family: tahoma;
      	font-size: 90%;
      	font-weight: bold;
      	text-decoration: none;
      	background-color: #17b;
      	color: white;
      	float:left;
      }
      
      a:link.extenser, a:visited.extenser, a:link.fixedextenser, a:visited.fixedextenser {
      	float:right; 
      	padding-left:2pt;
      	margin-left:4pt
      }
      
      span.typeglyph, span.typeglyphx {
      	padding: 0 0.2em 0 0;
      	margin: 0;
      }
      
      span.extenser, span.extenserx, span.fixedextenser {	
      	margin-top:1.2pt;
      }
      
      span.typeglyph, span.extenser, span.fixedextenser {
      	font-family: webdings;
      }
      
      span.fixedextenser {
      	display:none;
      	position:fixed;
      	right:6px;
      }
      
      td.typeheader:hover .fixedextenser {
      	display:block
      }
      
      span.typeglyphx, span.extenserx {
      	font-family: arial;
      	font-weight: bold;
      	margin: 2px;
      }
      
      table.group {
      	border: none;
      	margin: 0;
      }
      
      td.group {
      	border: none;
      	padding: 0 0.1em;
      }
      
      div.spacer { margin: 0.6em 0; }
      
      table.headingpresenter {
      	border: none;
      	border-left: 3px dotted #1a5;
      	margin: 1em 0em 1.2em 0.15em;
      }
      
      th.headingpresenter {
      	font-family: Arial;
      	border: none;
      	padding: 0 0 0.2em 0.5em;
      	background-color: white;
      	color: green;
      	font-size: 110%;        
      }
      
      td.headingpresenter {
      	border: none;
      	padding: 0 0 0 0.6em;
      }
      
      td.summary { 
      	background-color: #def;
      	color: #024;
      	font-family: Tahoma;
      	padding: 0 0.1em 0.1em 0.1em;
      }
      
      td.columntotal {
      	font-family: Tahoma;
      	background-color: #eee;
      	font-weight: bold;
      	color: #17b;
      	font-size:90%;
      	text-align:right;
      }
      
      span.graphbar {
      	background: #17b;
      	color: #17b;
      	margin-left: -2px;
      	margin-right: -2px;
      }
      
      a:link.graphcolumn, a:visited.graphcolumn {
      	color: #17b;
      	text-decoration: none;
      	font-weight: bold;
      	font-family: Arial;
      	font-size: 110%;
      	letter-spacing: -0.2em;	
      	margin-left: 0.3em;
      	margin-right: 0.1em;
      }
      
      a:link.collection, a:visited.collection { color:green }
      
      a:link.reference, a:visited.reference { color:blue }
      
      i { color: green }
      
      em { color:red; }
      
      span.highlight { background: #ff8 }
      
      code { font-family: Consolas }
      
      code.xml b { color:blue; font-weight:normal }
      code.xml i { color:maroon; font-weight:normal; font-style:normal }
      code.xml em { color:red; font-weight:normal; font-style:normal }
          </style>
      
          
        </head>
      <body><div class="spacer"><table id="t1"><tr><td class="typeheader" colspan="3">List&lt;Person&gt; (4 items)<span class="fixedextenser">4</span></td></tr><tr><th title="System.Guid">ID</th><th title="UserQuery+Account">PrivateAccount</th><th title="UserQuery+Account">SharedAccount</th></tr><tr><td>ab65bd04-1789-462d-88b5-6a99ab3ded35</td><td><table id="t2"><tr><td class="typeheader" colspan="2">Account<span class="fixedextenser">4</span></td></tr><tr id="sum3"><td colspan="2" class="summary">UserQuery+Account</td></tr><tr><th class="member" title="System.Guid">AccountId</th><td>aaaaaaaa-4525-4bfe-9e2c-a7afff0dda1f</td></tr><tr><th class="member" title="System.Decimal">Amount</th><td>100</td></tr></table></td><td><i>null</i></td></tr><tr><td>594e4a34-be98-479f-b5b5-91bb29aff98e</td><td><i>null</i></td><td><table id="t4"><tr><td class="typeheader" colspan="2">Account<span class="fixedextenser">4</span></td></tr><tr id="sum5"><td colspan="2" class="summary">UserQuery+Account</td></tr><tr><th class="member" title="System.Guid">AccountId</th><td>eeeeeeee-4525-4bfe-9e2c-a7afff0dda1f</td></tr><tr><th class="member" title="System.Decimal">Amount</th><td>2000</td></tr></table></td></tr><tr><td>d6735efe-2c4b-4e87-a0cb-7aaf9539994f</td><td><table id="t6"><tr><td class="typeheader" colspan="2">Account<span class="fixedextenser">4</span></td></tr><tr id="sum7"><td colspan="2" class="summary">UserQuery+Account</td></tr><tr><th class="member" title="System.Guid">AccountId</th><td>cccccccc-4525-4bfe-9e2c-a7afff0dda1f</td></tr><tr><th class="member" title="System.Decimal">Amount</th><td>300</td></tr></table></td><td><table id="t8"><tr><td class="typeheader" colspan="2">Account<span class="fixedextenser">4</span></td></tr><tr id="sum9"><td colspan="2" class="summary">UserQuery+Account</td></tr><tr><th class="member" title="System.Guid">AccountId</th><td>ffffffff-4525-4bfe-9e2c-a7afff0dda1f</td></tr><tr><th class="member" title="System.Decimal">Amount</th><td>3000</td></tr></table></td></tr><tr><td>dad6db35-ed55-49b1-a9ff-4ddb1a3a2989</td><td><i>null</i></td><td><i>null</i></td></tr></table></div><div class="spacer"><table id="t10"><tr><td class="typeheader" colspan="3">List&lt;PersonWithAmounts&gt; (4 items)<span class="fixedextenser">4</span></td></tr><tr><th title="System.Guid">PersonID</th><th title="System.Decimal">PAmount</th><th title="System.Decimal">SAmount</th></tr><tr><td>ab65bd04-1789-462d-88b5-6a99ab3ded35</td><td class="n">100</td><td class="n">0</td></tr><tr><td>d6735efe-2c4b-4e87-a0cb-7aaf9539994f</td><td class="n">300</td><td class="n">3000</td></tr><tr><td>594e4a34-be98-479f-b5b5-91bb29aff98e</td><td class="n">0</td><td class="n">2000</td></tr><tr><td>dad6db35-ed55-49b1-a9ff-4ddb1a3a2989</td><td class="n">0</td><td class="n">0</td></tr><tr><td title="Totals" class="columntotal"></td><td title="Total=400&#xD;&#xA;Average=100" class="columntotal">400</td><td title="Total=5000&#xD;&#xA;Average=1250" class="columntotal">5000</td></tr></table></div></body>
      </html>

1 个答案:

答案 0 :(得分:0)

假设3个查询是为了表示无法更改的3个列表,我建议最简单的解决方案是提取组合答案所需的部分:

var PAccountOnly = from p in PAccount where p.SharedAccount == null select p;
var SAccountOnly = from s in SAccount where s.PrivateAccount == null select s;
var PandSAccounts = from p in PAccount
                   join s in SAccount on p.PersonID equals s.PersonID
                   select new PersonWithAmounts { PersonID = p.PersonID, PAmount = p.PAmount, SAmount = s.SAmount };
var allAccounts = PAccountOnly.Concat(SAccountOnly).Concat(PandSAccounts).Concat(noAccount).ToList();