2016-01-23 2 views
1

Я хочу отфильтровать List с использованием Linq Where/Select, используя значение ключей в Dictionary, как показано в программе, мое текущее решение имеет ряд ограничений.Отфильтровать список, используя ключи словаря

Dictionary относится к пользовательскому вводу из пользовательского интерфейса, поэтому он может содержать набор значений вместо одного значения для заданного ключа.

Любой указатель, который поможет мне в правильном направлении.

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 AND Name = G? Или у вас есть ID = 3 OR Name = G? Может ли словарь содержать более двух элементов? –

+0

Результат должен быть комбинацией значений, то есть ID = 3 AND Name = G здесь. Да, он может содержать ключи, которые не являются частью бизнес-объекта в небольшом углу, но теперь я был бы рад предположить, что словарь может содержать только допустимые ключи. –

+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); 
Смежные вопросы