簡體   English   中英

Linq獲取自定義對象的列表,其中字典屬性中包含的某個值等於一個特定值

[英]Linq to get list of custom objects where a certain value contained within dictionary property equals a specific value

我正在努力解決此問題,並且已經搜索了多種方法,但似乎找不到答案。 我從其他人那里繼承了此應用,因此需要向該應用添加一些功能。 之前我與字典和linq的合作並不多,所以我一直在搜索並嘗試獲取知識來做我需要做的事情。

有一個具有以下屬性的類(刪除了一些本討論不需要的屬性):

class EmailRecord
{
    public Dictionary<string, List<string>> emails = new Dictionary<string, List<string>>();
    public string RecordID { get; set; }

[其次是其他屬性和構造函數...]

創建對象時,電子郵件屬性將在鍵中包含模板字符串,並在值中包含包含電子郵件地址的字符串列表。 就我的目的而言,我不需要知道密鑰中的內容。

我有一個稱為allRecords的EmailRecord對象列表。 我需要查詢allRecords以獲得所有EmailRecord對象的列表,其中emails字典屬性的值列表包含一個特定的電子郵件地址,該地址已存儲在一個名為receiveEmail的變量中。 密鑰無關緊要,電子郵件顯示多少次也無關緊要。 如果電子郵件出現在emails屬性的值中的任何地方,我只需要結果中包含的對象的實例。 在EmailRecord的實例中,電子郵件詞典屬性可以具有兩個鍵,並且在每個鍵內,該值的字符串列表中包含多個電子郵件。 我不需要限制於特定的鍵,我只需要知道在該字典中任何位置的電子郵件字符串列表中是否存在任何電子郵件。

我已經嘗試了一些方法,最近的方法是這樣的(不起作用):

var results = EmailRecords
    .SelectMany(x => x.emails)
    .Where(x => x.Value.Contains(recipientEmail));

上面的代碼似乎只是在返回dictionary屬性,而不是整個對象。

我希望能夠像這樣遍歷結果:

foreach (EmailRecord foundRecord in results) {
    ...do work here
}

在嘗試學習Linq時有什么想法或建議可以幫助我嗎? 預先感謝您提供的任何幫助。

如果要遍歷EmailRecord對象,該對象的emails屬性之一包含recipientEmail ,則首先需要有一個EmailRecord列表。 然后搜索他們。 以下應該可以解決問題。

List<EmailRecord> EmailRecords = new List<EmailRecord>();

//Fill the EmailRecords somewhere

foreach (KeyValuePair<string, List<string>> emailfoundRecord in 
                  EmailRecords.emails.Where(x => x.Value.Contains(recipientEmail)))
 {
   //do work here       
 }

當您調用EmailRecords.SelectMany(x => x.Emails) ,您得到的是IEnumerable<KeyValuePair<string, List<string>>>或類似名稱。 顯然,這不是您追求的結果,因為它剝奪了所有其他信息。

使用LINQ,在每個階段要考慮的第一件事是您期望從查詢中獲得什么。 在這種情況下,查詢結果應該是EmailRecord實例的枚舉,這也是我們要輸入的內容。最簡單的過濾列表是使用Where方法,因此您應該在其中進行所有工作

接下來確定您的過濾條件,並寫出適合的過濾謂詞。 對於任何給定的EmailRecord我們想確定是否有任何詞典條目包含特定的電子郵件地址。 由於字典值是列表,因此我們將使用Contains進行實際比較,並使用Any測試字典本身。

看起來像這樣:

var filtered = EmailRecords.Where(e => 
    e.Emails.Any(kv => 
        kv.Value.Contains(recipientEmail)
    )
);

這是可行的,因為字典也是可枚舉的,枚舉中的每個條目都是鍵/值對。

當找到單個匹配條目時,將停止使用Any而不是針對每個EmailRecord實例繼續到Emails字典的末尾。 如果有很多電子郵件,並且您期望有大量選擇,那么這可能會節省一些時間。 但是,可能不是,因為通常這種結構中沒有很多重復的電子郵件地址。

取決於您要執行此操作的頻率,但是構建查詢和查詢可能更快。 假設您的EmailRecords列表不經常更改,並且您正在進行大量此類查找,則可以大大提高速度。

我將使用Dictionary<string, EmailRecord[]>進行查找,因為一旦我們獲得了所有成對的電子郵件地址和EmailRecord對象的列表,它的構建(相當)容易:

var emailReferences = EmailRecords.SelectMany(e => 
    e.Emails.SelectMany(kv => 
        kv.Value.Select(v => 
            new { address = v, record = e }
        )
    )
);

var lookup = 
    emailReferences
    .GroupBy(i => i.address, i => i.record)
    .ToDictionary(g => g.Key, g => g.ToArray());
;

通過此操作,您將可以非常簡單,快速地找到一個電子郵件地址並獲取其引用EmailRecord實例:

EmailRecord[] filtered = null;
lookup.TryGetValue(recipientEmail, out filtered);

每次查找的速度將比上面的LINQ更快,但是對於大型列表,該設置可能會消耗大量的時間和內存。 如果您的列表很小或經常更改(由於每次更改都必須重新生成查找或至少使查找無效),則這不會提高程序的速度。


順便說一句,這是我在處理以List<>為值的字典時使用的擴展方法:

public static partial class extensions
{
    public static Dictionary<TKey, List<TElem>> Add<TKey, TElem>(this Dictionary<TKey, List<TElem>> dict, TKey key, TElem value)
    {
        List<TElem> list;
        if (dict.ContainsKey(key))
            list = dict[key];
        else
            dict[key] = list = new List<TElem>();

        list.Add(value);
        return dict;
    }
}

它有助於使您的添加內容更簡單易讀。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM