【问题标题】:How to implement efficient filtering logic in Python?如何在 Python 中实现高效的过滤逻辑?
【发布时间】:2014-07-15 00:14:22
【问题描述】:

我正在尝试创建一个程序来存储

  1. 水果名称
  2. 水果类型
  3. 果色
  4. 水果大小

并根据要求将它们显示给用户。将为用户提供预定义的选项以供选择。像这样的:

我的数据库表会是这样的:

现在,我正在尝试实现一个过滤器功能,让用户选择

  • 水果类型
  • 果色
  • 水果大小

它会给出所有具有上述属性的Fruit Names。但是现在,我有一个额外的选项,“全部”。

假设我已经查询了所有水果的数据并将它们存储在字典中,如下所示:

myfruits = { 'apple':('fleshy','red','medium'),
            'orange':('fleshy','orange','medium'),
             'peanut':('dry','red','small'),...}

如何获取具有用户选择的三个属性的水果名称列表? (例如,如果用户选择了“肉质”类型、“全部”颜色、“全部”尺寸——它应该返回['apple','orange']。)

我曾想过使用if 语句,但随着属性数量的增加,我将不得不写很多行ifelse,我认为这不可行。

我在 Windows XP SP3 32 位上使用 Python 2.7 和 PyQt 4 和 SQLite 3 数据库。

【问题讨论】:

    标签: python filter sqlite pyqt logic


    【解决方案1】:

    我会在这里使用SQLAlchemy 来处理数据库层,要么使用它as an ORM,要么只使用generate the SQL expressions

    这使您可以动态生成过滤器;您可以循环遍历过滤器并且特定过滤器尚未设置为“全部”,通过它来限制查询。

    使用 SQLAlchemy 来生成 SQL 表达式如下所示:

    from sqlalchemy.sql import select
    
    fruit_query = select([fruits])
    for filtername in ui_filters:
        filtervalue = obtain_filter_value_for(filtername)
        if filtervalue != 'All':
            fruit_query = fruit_query.where(filtername == filtervalue)
    

    替代方法是手动生成WHERE 子句:

    query = 'SELECT * FROM fruits'
    params = []
    whereclauses = []
    
    for filtername in ui_filters:
        filtervalue = obtain_filter_value_for(filtername)
        if filtervalue != 'All':
            whereclauses.append('{} = ?'.format(filtername))
            params.append(filtervalue)
    
    if whereclauses:
        query = '{} WHERE {}'.format(query, ' AND '.join(whereclauses))
    
    cursor.execute(query, params)
    

    但请注意,SQLAlchemy 表达式引擎更加灵活且不易出错。很快您就会想要添加更复杂的过滤器(在范围内搜索、文本搜索、在“或”表达式中组合过滤器),SQLAlchemy 可以让表达式的生成变得非常很多,真的。

    【讨论】:

    • 有没有什么好的方法可以通过内置模块来实现它?对初学者更友好的东西?不过感谢您的帮助。
    • @ChrisAung:您必须手动生成WHERE 子句。我已经为此添加了说明。但实际上,SQLAlchemy 不仅仅是将过滤器与AND 连接在一起,它更容易。很快您就会需要文本搜索(ILIKE 查询)或范围(BETWEEN)等,突然之间,SQLAlchemy SQL 生成比处理查询字符串要容易得多。 :-)
    【解决方案2】:

    如果您已经查询出所有数据,一个简单的方法是简单地使用filter 函数:

    def predicate(fruit_type, fruit_color, fruit_size):
        def _predicate(fruit):
            if not fruit_type == 'All' and not fruit_type == fruit[1][0]:
                return False
            if not fruit_color == 'All' and not fruit_color == fruit[1][1]:
                return False
            if not fruit_size == 'All' and not fruit_size == fruit[1][2]:
                return False
            return True
        return _predicate
    
    query_type = 'All'
    query_color = 'All'
    query_size = 'All'
    myfruits = {}
    my_filtered_fruit = list(filter(predicate(query_type, query_color, query_size), myfruits.items()))
    

    另一种方法是定义一个对象Predicate,它有一个视图(过滤器的名称)和关联的过滤器函数:

    class Predicate:
        def __init__(self, predicate, view):
            self.predicate = predicate
            self.view = view
    
    # Creation of the predicates :
    all_color = Predicate(lambda fruit: True, 'All colors')
    red_color = Predicate(lambda fruit: fruit[2] == 'red')
    # ...
    
    # Then you have to generate your select form. I don't remember exactly the PyQt4 doc but it's not the harder part.
    
    predicates = getAllSelected() # I guess you know how to get this kind of function
    
    myfruits = {}
    my_filtered_fruits = myfruits.items()
    for pred in predicates:
        my_filtered_fruit = filter(lambda x: pred(x[1]), my_filtered_fruit)
    my_filtered_fruit = list(my_filtered_fruit)
    

    【讨论】:

      猜你喜欢
      • 2018-02-21
      • 2015-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-20
      • 1970-01-01
      相关资源
      最近更新 更多