2017-08-03 110 views
1

我試圖找到買方的所有發票,通過買方名稱搜索(包含和等於過濾器)。尋找最乾淨的方式來做到這一點。 我有一個買家名單。C#LINQ。按對象名稱屬性或名稱部分搜索對象

List <Buyer> AllBuyers; 

,買受人爲:

public class Buyer 
    { 
     public string BuyerIdentifier{ get; set; } 
     public string Name { get; set; } 
    } 

我有發票的買家名單。

List <Invoice> AllInvoices; 

而且發票是

public class Invoice 
    { 
     public string InvoiceID { get; set; } 
     public string BuyerID { get; set; } 
     public string Amount{ get; set; } 
    } 

我目前在做什麼:

List<string> BuyerIDs = new List<string> { }; 
foreach (Invoice inv in AllInvoices) 
{ 
    if (!(BuyerIDs.Contains(inv.BuyerID))) 
    { 
     // add BuyerID to list if it's not already there. Getting id's that are present on invoices and whose Buyer names match using contains or equals 
     BuyerIDs.Add(AllBuyers.First(b => b.BuyerIdentifier == inv.BuyerID 
      && (b.Name.IndexOf(SearchValue, StringComparison.OrdinalIgnoreCase) >= 0)).BuyerIdentifier); 
    }             
} 
Invoices = AllInvoices.FindAll(i=> BuyerIDs.Contains(i.BuyerID)); 

LINQ查詢語法有點容易,我比LINQ方法加入明白。所以經過下面我的答覆我現在這樣做:

Invoices = (from buyer in AllBuyers 
       join invoice in AllInvoices on buyer.BuyerIdentifier equals invoice.BuyerID 
       where buyer.Name.IndexOf(SearchValue, StringComparison.OrdinalIgnoreCase) >= 0         
       select invoice).ToList(); 
+2

請問你的代碼的工作?如果確實如此,並且您只是希望改進代碼,則此問題可能屬於[Code Review Stack Exchange](https://codereview.stackexchange.com/),而不是此處。否則,你有什麼問題,或者你看到了什麼錯誤? –

+0

它的工作原理,我只是想知道是否有一個更好的方式在LINQ做到沒有foreach循環,如果條件。 – Razkar

+0

我不知道你在做什麼,但你可能只是做一個加入 –

回答

1

這裏就是我創建BuyerIdentifier字典作爲鍵和值發票列表的建議:

var dict = AllBuyers.ToDictionary(k => k.BuyerIdentifier, 
       v => AllInvoices.Where(i => i.BuyerID == v.BuyerIdentifier).ToList()); 

然後你就可以訪問像這樣一個特定買方發票清單:

List<Invoice> buyerInvoices = dict[buyerId]; 
+3

這是非常低效的。 – Iucounu

0

這應該爲你工作:

var InvoiceGrouping = AllInvoices.GroupBy(invoice => invoice.BuyerID) 
           .Where(grouping => AllBuyers.Any(buyer => buyer.BuyerIdentifier == grouping.Key && buyer.Name.IndexOf(pair.Value, StringComparison.OrdinalIgnoreCase) >= 0)); 

您最終得到的是一個以買方ID爲關鍵字和所有發票作爲值的分組。在其結束,因爲IGrouping工具IEnumerable,展平了分組到單一的價值枚舉

var Invoices = AllInvoices.GroupBy(invoice => invoice.BuyerID) 
          .Where(grouping => AllBuyers.Any(buyer => buyer.BuyerIdentifier == grouping.Key && buyer.Name.IndexOf(pair.Value, StringComparison.OrdinalIgnoreCase) >= 0)) 
          .SelectMany(grouping => grouping); 

注意添加SelectMany

如果你想要發票的只是一個平面列表,你可以像這樣。

2

如果你需要的是發票,您可以加入你的兩個集合,過濾器,並選擇發票

AllBuyers.Join(AllInvoices, 
      a => a.BuyerIdentifier, 
      a => a.BuyerID, 
      (b, i) => new { Buyer = b, Invoice = i }) 
    .Where(a => a.Buyer.Name.Contains("name")) 
    .Select(a => a.Invoice).ToList(); 

如果你想購房者爲好,只是離開了.Select(a => a.Invoice)。 字符串的Contains方法也會匹配equals。

+0

謝謝,我想加入是我正在尋找。至於Contains,我希望不區分大小寫的搜索,並且不想使用toLower()。 – Razkar

+1

我認爲在執行加入之前,您可以從買家過濾中受益。我想這是OP最後一次編輯後的意圖。也就是說,他打算通過名稱上的搜索值篩選買家(這可能會大大減少買家的完整列表) –

+0

只需要一次加入警告,如果您無法保證每名買家只有一次在列表中,您會在結果中獲得重複的發票。 –

0

作爲ILookup變形金剛迷,這將是我的做法:

var buyerMap = AllBuyers 
    .Where(b => b.Name.IndexOf(SearchValue, StringComparison.OrdinalIgnoreCase) >= 0) 
    .ToDictionary(b => b.BuyerIdentifier); 

var invoiceLookup = AllInvoices 
    .Where(i => buyerMap.ContainsKey(i.BuyerID)) 
    .ToLookup(x => x.BuyerID); 

foreach (var invoiceGroup in invoiceLookup) 
{ 
    var buyerId = invoiceGroup.Key; 
    var buyer = buyerMap[buyerId]; 
    var invoicesForBuyer = invoiceGroup.ToList(); 

    // Do your stuff with buyer and invoicesForBuyer 
} 
+0

其實,你不需要查詢,'GroupBy'就夠了,可能更乾淨 –