【问题标题】:Filter a List using Dictionary keys使用字典键过滤列表
【发布时间】:2017-08-26 00:07:03
【问题描述】:

我想使用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
                       );   
}

【问题讨论】:

  • 预期输出是多少? ID = 3 AND Name = G 的业务对象?或者 ID = 3 OR Name = G?字典可以包含两个以上的项目吗?
  • 结果应该是值的组合,即 ID = 3 AND Name = G 在这里。是的,它可以包含在少数情况下不属于业务实体的键,但现在我最好假设字典只能包含有效键
  • 但是在这种情况下,字典中有三四个项目是什么意思?例如,如果字典包含以下内容:ID = 2、ID = 4、NAME = E,该怎么办? NAME = H?
  • @YacoubMassad 这只是意味着后过滤,可能有一个空的结果,因此没有可用的匹配
  • 因此,如果字典中有多个 ID 具有不同的值,则结果将为空。 NAME也一样,对吧?

标签: c# linq dictionary


【解决方案1】:

这是一种解决方案:

//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】:

执行此操作的通用方法是使用反射和缓存这些属性以提高性能,因为反射可能非常慢。您还可以使用泛型,以便它适用于任何类型。您可能正在寻找类似以下的内容。

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();
} 

【讨论】:

  • 这很容易,非常感谢,提供了多个组合的所有有效值
【解决方案3】:

这是我的解决方案(返回预期结果):

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

【讨论】:

    【解决方案4】:

    字典只能有唯一的键。如果您多次拥有相同的键,则键的值必须是一个集合。见下面的代码

    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; }
            }
    
        }
    }
    

    【讨论】:

    • 这绝不是一个解决方案,它没有为问题陈述提供解决方案
    猜你喜欢
    • 2018-05-01
    • 2020-10-30
    • 2023-01-14
    • 2020-04-08
    • 2022-12-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-17
    相关资源
    最近更新 更多