如何在列表上应用多个过滤条件(同时)? [英] How to apply multiple filter conditions (simultaneously) on a list?

查看:223
本文介绍了如何在列表上应用多个过滤条件(同时)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下与 .NET 4.0 框架的C#代码。这是指规范模式后创建的 - 由杰夫佩兰



的GetProducts()内使用的定义(硬编码)的条件方法。还有一种方法叫 GetProductsBasedOnInputFilters()。在该方法的规格列表被制成参数的方法。





什么是名单上应用这些过滤器的最佳方法生产的产品,这种方法



注意:我曾尝试运用的FindAll 一个的foreach 循环中条款并添加在列表的结果。但是,这个逻辑是不正确 - 只有那些满足所有的条件需要返回的项目



注意:在productSpeifications列表规格数量会根据用户输入



注意:中提到的方法动态地构建LINQ过滤器中的任何()方法? 似乎是有用的。但是我不知道如何在这里使用这种方法,因为我处理的规格列表;没有泛型委托



过滤方法



 公共静态类ProductFilterHelper 
{
公共静态列表<产品与GT;的GetProducts(列表<产品与GT;清单)
{
双priceLimit = 100;

//首先::
//名单<产品与GT; selectedList = list.FindAll(新OnSaleSpecification()IsSatisfiedBy);

//第二::
// AndSpecification<产品与GT;规格=新AndSpecification<产品及GT;(新OnSaleSpecificationForProduct(),新PriceGreaterThanSpecificationForProduct(priceLimit));
//名单<产品与GT; selectedList = list.FindAll(spec.IsSatisfiedBy);


//第三名:
名单,LT;产品与GT; selectedList = list.FindAll(新OnSaleSpecificationForProduct()
。而(新PriceGreaterThanSpecificationForProduct(priceLimit))
。而(新PriceGreaterThan105())
.IsSatisfiedBy
);

返回selectedList;
}

公共静态列表<产品与GT; GetProductsBasedOnInputFilters(列表<产品与GT; productList的,列表与LT;规格及LT;产品与GT;> productSpeifications)
{
名单,LT;产品与GT; selectedList =新的List<产品及GT;();

的foreach(规格及LT;产品>在productSpeifications规范)
{
名单,LT;产品与GT; currentList = productList.FindAll(specification.IsSatisfiedBy);

如果(currentList =空&放大器;!&放大器; currentList.Count大于0)
{
的foreach(在currentList产品P)
{
(!selectedList.Contains(p))如果
{
selectedList.Add(对);
}
}
}
}

返回selectedList;
}

}



客户端

 类节目
{

静态无效的主要(字串[] args)
{

名单,LT;产品与GT;名单=新名单,LT;产品>();

产品P1 =新产品(假,99);
产品P2 =新产品(真,99);
产品P3 =新产品(真正的,101);
产品P4 =新产品(真正的,110);
产品P5 =新产品(假的,110);

list.Add(P1);
list.Add(P2);
list.Add(P3);
list.Add(P4);
list.Add(P5);

双priceLimit = 100;

名单,LT;规格及LT;产品与GT;>规格=新的List<规格及LT;产品与GT;>();
specifications.Add(新OnSaleSpecificationForProduct());
specifications.Add(新PriceGreaterThanSpecificationForProduct(priceLimit));
specifications.Add(新PriceGreaterThan105());

名单,LT;产品与GT; selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(列表,规格);

Console.ReadKey();
}

}



摘要规格

 公共抽象类规格及LT; T> 
{
公共抽象BOOL IsSatisfiedBy(T OBJ);

公共AndSpecification< T>和(规格及LT; T>规范)
{
返回新AndSpecification< T>(这一点,规范);
}

公共OrSpecification< T>或(规格及LT; T>规范)
{
返回新OrSpecification< T>(这一点,规范);
}

公共NotSpecification< T>没有(规格及LT; T>规范)
{
返回新NotSpecification< T>(这一点,规范);
}
}

公共抽象类CompositeSpecification< T> :指标LT; T>
{
保护只读规格及LT; T> _左边;
保护只读规格及LT; T> _右边;

公共CompositeSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
{
_leftSide = leftSide;
_rightSide = rightSide;
}
}



通用规格

 公共类AndSpecification< T> :CompositeSpecification< T> 
{
公共AndSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
:基地(leftSide,rightSide)
{

}

酒店的公共覆盖布尔IsSatisfiedBy(T OBJ)
{
返回_leftSide.IsSatisfiedBy(OBJ)及和放大器; _rightSide.IsSatisfiedBy(OBJ);
}
}

公共类OrSpecification< T> :CompositeSpecification< T>
{
公共OrSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
:基地(leftSide,rightSide)
{
}

酒店的公共覆盖布尔IsSatisfiedBy(T OBJ)
{
返回_leftSide.IsSatisfiedBy(OBJ)|| _rightSide.IsSatisfiedBy(OBJ);
}
}

公共类NotSpecification< T> :CompositeSpecification< T>
{
公共NotSpecification(规格及LT; T> leftSide,规格及LT; T> rightSide)
:基地(leftSide,rightSide)
{
}

酒店的公共覆盖布尔IsSatisfiedBy(T OBJ)
{
返回_leftSide.IsSatisfiedBy(OBJ)及和放大器; !_rightSide.IsSatisfiedBy(OBJ);
}
}



产品规格

 公共类OnSaleSpecificationForProduct:指标LT;产品与GT; 
{
公众覆盖布尔IsSatisfiedBy(产品产品)
{
返回product.IsOnSale;
}
}

公共类PriceGreaterThanSpecificationForProduct:指标LT;产品与GT;
{
私人只读双_price;
公共PriceGreaterThanSpecificationForProduct(双价)
{
_price =价格;
}

公众覆盖布尔IsSatisfiedBy(产品产品)
{
返回product.Price> _价钱;
}
}

公共类PriceGreaterThan105:指标LT;产品与GT;
{

公众覆盖布尔IsSatisfiedBy(产品产品)
{
返回product.Price> 105;
}
}



实体

 公共类产品
{
私人布尔_isOnSale;
私人双_price = 0.0;

公共产品(布尔isOnSale)
:这(isOnSale,0.0)
{
_isOnSale = isOnSale;
}

公共产品(双价)
:这个(假的,价格)
{
_price =价格;
}

公共产品(布尔isOnSale,双价)
{
_price =价格;
_isOnSale = isOnSale;
}

公共BOOL IsOnSale
{
{返回_isOnSale; }
}

公共双价
{
{返回_price; }
}
}



参考




  1. 规范模式 - 由杰夫·佩兰

  2. 流利的接口和方法链在C#

  3. Avoid浏览列表多个时间使用LINQ,具有动态条件(过滤器)

  4. 动态地构建LINQ过滤器中的任何()方法?


解决方案

您可以做的几件事情之一:




  • 通过堆叠组合过滤器其中,在@ Lijo的答案


  • 检查每个项目的所有规格上对方,就像上面调用:

     收益productList的
    。凡(p => specifications.All(PS => ps.IsSatisfiedBy(P))
    .ToList()


  • <李>

    创建复合与规范,接受多个孩子,而不是只有两个:

     公共类AndSpecification< T> ; :ISpecification< T> 
    {
    私人ISpecification< T> [] _components;

    公共AndSpecification(ISpecification< T> []组件)
    {
    _components =组件;
    }

    公共BOOL IsSatisfiedBy(T项目)
    {
    返回components.All(C => c.IsSatisfiedBy(项目));
    }
    }




然后,你可以这样做:

  VAR allFiltersSpecification =新AndSpecification(规格)
返回productList.Where(allFiltersSpecification.IsSatisfiedBy );


I have following C# code with .Net 4.0 framework. This is created after referring The Specification Pattern - by Jeff Perrin

In the GetProducts() the conditions to be used are defined (hard coded) inside the method. There is another method named GetProductsBasedOnInputFilters(). In this method the list of specifications are made as parameter to the method.

QUESTION

What is the best way to apply these filters on the list of products, in this method?

Note: I have tried applying the FindAll clause inside a foreach loop and adding the results in a list. But that logic is incorrect - only those items that satisfy all of the conditions need to be returned.

Note: The number of specifications in the productSpeifications list will vary based on user input

Note: The Approach mentioned in "Dynamically build LINQ filter for the Any() method?" seems useful. However I am not sure how to use this approach here since I am dealing with List of specifications; not generic delegates.

Filter Methods

public static class ProductFilterHelper
{
    public static List<Product> GetProducts(List<Product> list)
    {
        double priceLimit = 100;

        //FIRST::
        //List<Product> selectedList =  list.FindAll(new OnSaleSpecification().IsSatisfiedBy);

        //SECOND::
        //AndSpecification<Product> spec = new AndSpecification<Product>(new OnSaleSpecificationForProduct(), new PriceGreaterThanSpecificationForProduct(priceLimit));
        //List<Product> selectedList = list.FindAll(spec.IsSatisfiedBy); 


        //THIRD:
        List<Product> selectedList = list.FindAll(new OnSaleSpecificationForProduct()
                                                       .And(new PriceGreaterThanSpecificationForProduct(priceLimit))
                                                       .And(new PriceGreaterThan105())
                                                       .IsSatisfiedBy
                                                  );

        return selectedList;
    }

    public static List<Product> GetProductsBasedOnInputFilters(List<Product> productList, List<Specification<Product>> productSpeifications)
    {
        List<Product> selectedList = new List<Product>();

        foreach (Specification<Product> specification in productSpeifications)
        {
            List<Product> currentList = productList.FindAll(specification.IsSatisfiedBy);

            if (currentList != null && currentList.Count > 0)
            {
                foreach (Product p in currentList)
                {
                    if (!selectedList.Contains(p))
                    {
                        selectedList.Add(p);
                    }
                }
            }
        }

        return selectedList;
    }        

}

Client

class Program
{

    static void Main(string[] args)
    {

        List<Product> list = new List<Product>();

        Product p1 = new Product(false, 99);
        Product p2 = new Product(true, 99);
        Product p3 = new Product(true, 101);
        Product p4 = new Product(true, 110);
        Product p5 = new Product(false, 110);

        list.Add(p1);
        list.Add(p2);
        list.Add(p3);
        list.Add(p4);
        list.Add(p5);

        double priceLimit = 100;

        List<Specification<Product>> specifications = new List<Specification<Product>>();
        specifications.Add(new OnSaleSpecificationForProduct());
        specifications.Add(new PriceGreaterThanSpecificationForProduct(priceLimit));
        specifications.Add(new PriceGreaterThan105());

        List<Product> selectedList = ProductFilterHelper.GetProductsBasedOnInputFilters(list, specifications);

        Console.ReadKey();
    }

}

Abstract Specifications

public abstract class Specification<T>
{
    public abstract bool IsSatisfiedBy(T obj);

    public AndSpecification<T> And(Specification<T> specification)
    {
        return new AndSpecification<T>(this, specification);
    }

    public OrSpecification<T> Or(Specification<T> specification)
    {
        return new OrSpecification<T>(this, specification);
    }

    public NotSpecification<T> Not(Specification<T> specification)
    {
        return new NotSpecification<T>(this, specification);
    }
}

public abstract class CompositeSpecification<T> : Specification<T>
{
    protected readonly Specification<T> _leftSide;
    protected readonly Specification<T> _rightSide;

    public CompositeSpecification(Specification<T> leftSide, Specification<T> rightSide)
    {
        _leftSide = leftSide;
        _rightSide = rightSide;
    }
}

Generic Specifications

public class AndSpecification<T> : CompositeSpecification<T>
{
    public AndSpecification(Specification<T> leftSide, Specification<T> rightSide)
        : base(leftSide, rightSide)
    {

    }

    public override bool IsSatisfiedBy(T obj)
    {
        return _leftSide.IsSatisfiedBy(obj) && _rightSide.IsSatisfiedBy(obj);
    }
}

public class OrSpecification<T> : CompositeSpecification<T>
{
    public OrSpecification(Specification<T> leftSide, Specification<T> rightSide)
        : base(leftSide, rightSide)
    {
    }

    public override bool IsSatisfiedBy(T obj)
    {
        return _leftSide.IsSatisfiedBy(obj) || _rightSide.IsSatisfiedBy(obj);
    }
}

public class NotSpecification<T> : CompositeSpecification<T>
{
    public NotSpecification(Specification<T> leftSide, Specification<T> rightSide)
        : base(leftSide, rightSide)
    {
    }

    public override bool IsSatisfiedBy(T obj)
    {
        return _leftSide.IsSatisfiedBy(obj) && !_rightSide.IsSatisfiedBy(obj);
    }
}

Product Specifications

public class OnSaleSpecificationForProduct : Specification<Product>
{
    public override bool IsSatisfiedBy(Product product)
    {
        return product.IsOnSale;
    }
}

public class PriceGreaterThanSpecificationForProduct : Specification<Product>
{
    private readonly double _price;
    public PriceGreaterThanSpecificationForProduct(double price)
    {
        _price = price;
    }

    public override bool IsSatisfiedBy(Product product)
    {
        return product.Price > _price;
    }
}

public class PriceGreaterThan105 : Specification<Product>
{

    public override bool IsSatisfiedBy(Product product)
    {
        return product.Price > 105;
    }
}

Entity

public class Product
{
    private bool _isOnSale;
    private double _price = 0.0;

    public Product(bool isOnSale)
        : this(isOnSale, 0.0)
    {
        _isOnSale = isOnSale;
    }

    public Product(double price)
        : this(false, price)
    {
        _price = price;
    }

    public Product(bool isOnSale, double price)
    {
        _price = price;
        _isOnSale = isOnSale;
    }

    public bool IsOnSale
    {
        get { return _isOnSale; }
    }

    public double Price
    {
        get { return _price; }
    }
}

REFERENCES

  1. The Specification Pattern - by Jeff Perrin
  2. Fluent interfaces and Method Chaining in C#
  3. Avoid to browse a list multiple time with linq, with dynamic conditions (filter)
  4. Dynamically build LINQ filter for the Any() method?

解决方案

You can do one of several things:

  • Combine the filters by stacking Where invocations on top of each other, like in @Lijo's answer

  • Check all specifications on each item:

    return productList
      .Where(p => specifications.All(ps => ps.IsSatisfiedBy(p))
      .ToList()
    

  • Create a composite 'And' specification that accepts multiple children instead of just two:

    public class AndSpecification<T> : ISpecification<T>
    {
        private ISpecification<T>[] _components;
    
        public AndSpecification(ISpecification<T>[] components) 
        {
          _components = components;
        }
    
        public bool IsSatisfiedBy(T item) 
        {
          return components.All(c => c.IsSatisfiedBy(item));
        }
      }
    

Then you could do:

var allFiltersSpecification = new AndSpecification(specifications)
return productList.Where(allFiltersSpecification.IsSatisfiedBy);

这篇关于如何在列表上应用多个过滤条件(同时)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆