2016-01-23 79 views
1

我想使用Linq Where/Select過濾List,使用程序中顯示的Dictionary中的鍵值,我當前的解決方案有許多限制。使用字典鍵過濾列表

Dictionary引用來自UI的用戶輸入,因此它可能包含一組值而不是給定鍵的單個值。

任何指針,以幫助我一個正確的方向。

public class Business 
    { 
     public int ID { get; set; } 

     public string NAME { get; set; } 
    } 

void Main() 
{ 
    var businessList = new List<Business> 
    { 
     new Business {ID = 1,NAME = "A"}, 
     new Business {ID = 1,NAME = "B"}, 
     new Business {ID = 1,NAME = "C"}, 
     new Business {ID = 2,NAME = "D"}, 
     new Business {ID = 2,NAME = "E"}, 
     new Business {ID = 2,NAME = "F"}, 
     new Business {ID = 3,NAME = "G"}, 
     new Business {ID = 4,NAME = "H"}, 
     new Business {ID = 4,NAME = "I"}, 
     new Business {ID = 4,NAME = "J"}, 
     new Business {ID = 5,NAME = "K"}, 
     new Business {ID = 5,NAME = "L"} 
    }; 

    var filterDictionary = new Dictionary<string, object> 
    { 
     {"ID",3}, 
     {"NAME","G"} 
    }; 

    Expected Result: 
    ID Name 
    3  G 

    var filterDictionary = new Dictionary<string, object> 
    { 
     {"ID",new List<int>(){2,3}} 
    }; 

Expected Result: 
    ID Name 
    2  D 
    2  E 
    2  F 
    3  G 

Current Solution: 

    var result = businessList 
       .Select(x => filterDictionary.ContainsKey(typeof(Business).GetProperty("ID").Name) ? 
          x.ID == (int)filterDictionary[typeof(Business).GetProperty("ID").Name] ? x : null : null        
         ) 
       .Where(x => x!= null) 
       .Select(x => filterDictionary.ContainsKey(typeof(Business).GetProperty("NAME").Name) ? 
          x.NAME == (string)filterDictionary[typeof(Business).GetProperty("NAME").Name] ? x : null : null 
         ); 
} 
+3

什麼是預期的輸出?業務對象的ID = 3和名稱= G?或者ID = 3或名稱= G?字典可以包含兩個以上的項目嗎? –

+0

結果應該是這些值的組合,即ID = 3 AND Name = G out。是的,它可以包含在幾個角落案件中不屬於商業實體一部分的密鑰,但截至現在,我可以假設字典只能包含有效密鑰 –

+0

但是在這種情況下,這意味着有三個或四個項目在字典中?例如,如果字典包含以下內容:ID = 2,ID = 4,NAME = E? NAME = H? –

回答

1

一個通用的方法來做到這一點將屬性GetMethod使用反射和緩存這些來提高性能,因爲反射可能會很慢。您也可以使用泛型,以便它可以處理任何類型。類似以下內容可能是你正在尋找的東西。

private static List<T> FilterList<T>(IEnumerable<T> source, Dictionary<string, object> propertyFilters) 
{ 
    var properties = propertyFilters.Keys.Distinct() 
              .ToDictionary(x => x, x => typeof (T).GetProperty(x).GetGetMethod()); 

    IEnumerable<T> result = source.ToList(); 
    foreach (var propertyFilter in propertyFilters) 
    { 
     if (properties.ContainsKey(propertyFilter.Key)) 
     { 
      result = result.Where(x => 
      { 
       var invoke = properties[propertyFilter.Key].Invoke(x, new object[0]); 
       if (propertyFilter.Value is IList) 
       { 
        return ((IList)propertyFilter.Value).Cast<object>().Any(f => 
        { 
         return f.Equals(invoke); 
        }); 
       } 
       return invoke.Equals(propertyFilter.Value); 
      }); 
     } 
    } 
    return result.ToList(); 
} 
+0

這很有用,非常感謝,爲多種組合提供所有有效值 –

-1

字典只能有唯一的鍵。如果您有多次使用相同的密鑰,密鑰的值必須是一個集合。見下面

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace ConsoleApplication1 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Business> businessList = new List<Business> 
      { 
       new Business {ID = 1,NAME = "A"}, 
       new Business {ID = 1,NAME = "B"}, 
       new Business {ID = 1,NAME = "C"}, 
       new Business {ID = 2,NAME = "D"}, 
       new Business {ID = 2,NAME = "E"}, 
       new Business {ID = 2,NAME = "F"}, 
       new Business {ID = 3,NAME = "G"}, 
       new Business {ID = 4,NAME = "H"}, 
       new Business {ID = 4,NAME = "I"}, 
       new Business {ID = 4,NAME = "J"}, 
       new Business {ID = 5,NAME = "K"}, 
       new Business {ID = 5,NAME = "L"} 
      }; 

      Dictionary<int, List<string>> dict = businessList.AsEnumerable() 
       .GroupBy(x => x.ID, y => y.NAME) 
       .ToDictionary(x => x.Key, y => y.ToList()); 

     } 
     public class Business 
     { 
      public int ID { get; set; } 

      public string NAME { get; set; } 
     } 

    } 
} 
+0

絕不會是一個解決方案,它不提供解決方案的問題 –

3

下面的代碼一個解決方案:

//Calculate valid IDs from the dictionary 
List<int> valid_ids = 
    filterDictionary 
     .Where(x => x.Key == "ID") 
     .SelectMany(x => 
     { 
      if (x.Value is int) 
      { 
       return new[] {(int) x.Value}; 
      } 

      return (IEnumerable<int>) x.Value; 

     }).ToList(); 


//Calculate valid NAMEs from the dictionary 
List<string> valid_names = 
     filterDictionary 
     .Where(x => x.Key == "NAME") 
     .SelectMany(x => 
     { 
      if (x.Value is string) 
      { 
       return new[] { (string)x.Value }; 
      } 

      return (IEnumerable<string>)x.Value; 

     }).ToList(); 


IEnumerable<Business> query = businessList; 

if (valid_ids.Count > 0) 
    query = query.Where(x => valid_ids.Contains(x.ID)); 

if(valid_names.Count > 0) 
    query = query.Where(x => valid_names.Contains(x.NAME)); 

var result = query.ToList(); 
+2

Elegance ....... – Fattie

+0

必須同意一個非常優雅的解決方案,這是很容易理解 –

+0

你可以請幫我這個linq查詢:http ://stackoverflow.com/questions/38120664/how-to-group-by-on-2-child-entities-and-get-total-of-both-this-child-entities –

0

這是我在一排液(還給預期的結果):

var result = businessList.Where(bl => filterDictionary 
      .Count(fd => bl.GetType().GetProperty(fd.Key).GetValue(bl, null) == fd.Value) > 0);