【问题标题】:using a dictionary to filter a list of objects使用字典过滤对象列表
【发布时间】:2013-12-26 15:46:55
【问题描述】:

假设我有一个像这样的数据结构(对象列表):

[
 <--
    Name: Bob
    Job: Programmer
    Location: Salem
  -->,
 <--
    Name: Steve
    Job: Sales
    Location: New York
 -->,
 <--
    Name: Jeff
    Job: Programmer
    Location: New York
 -->
]

现在假设我有一个 Web 表单,它会返回一个字典,其中每个键都将引用对象中的一个字段。例如,假设我得到了这样的字典:

{"Name": [""], "Job": ["Programmer"], "Location": ["Salem", "New York"]}

这旨在返回塞勒姆和纽约位置的所有程序员:Bob 和 Jeff。它总是一个字符串列表的字典。我只想检查对象的字符串值是否包含这个字符串。

问题在于遍历字典的每个条目并确保每个对象都匹配字典的所有规范。 这是我当前的代码,它在逻辑上只创建一个对象列表,其中包含包含任何参数的任何对象,这不是我想要的:

return_list = []
filter_dictionary = dict(request.form)
for row in data:
  for key, value in filter_dictionary.iteritems():
    for obj in value:
      if obj in str(getattr(row, key)):
        return_list.append(row)
return return_list

我确信一定有一种更聪明、更好的方法来做到这一点,也许是涉及到集合的东西。我该怎么办?

返回值最终应该是一个对象列表,如原始示例中一样,但仅包含满足filter_dictionary 的所有规范的对象

【问题讨论】:

    标签: python python-2.7 flask


    【解决方案1】:

    其他人可能会给出更简洁的解决方案,但我认为与您现有代码最接近的调整是这样的:

    return_list = []
    filter_dictionary = dict(request.form)
    for row in data:
      match = True # we set to False if any attribute doesn't match
      for key, value in filter_dictionary.items():
        attrmatch = False # we need at least one match per attribute
        for obj in value:
          if obj in str(getattr(row, key)): attrmatch = True
        if not attrmatch: match = False
      if match: return_list.append(row)
    

    【讨论】:

    • 我相信这个解决方案的唯一问题是它只匹配列表中的一项。也就是说,如果它包含纽约或塞勒姆,则将其添加到列表中。也许我执行错了,但它似乎有这种行为
    【解决方案2】:

    我认为首先你需要改变你的输入:

    "Name": [""] 建议寻找名称为空字符串的程序员。我认为你应该使用[] 而不是[""],或者类似的东西。

    既然如此,那这个呢?

    return_list = []
    for row in data:
        if all((getattr(row, k) in v) or (not v) for k, v in filter_dictionary.iteritems()):
            return_list.append(thing)
    

    你当前的代码是这样的:

    return_list = []
    for row in data:
        if any((getattr(row, k) in v) or (not v) for k, v in filter_dictionary.iteritems()):
            return_list.append(thing)
    

    我认为以上方法或多或少是最好的方法(除了使用数据库)。

    但是既然你建议了套...

    首先你需要确保你的数据行类支持散列:

    class Person:
        def __init__(self, Name, Location, Job):
            self.Name = Name
            self.Location = Location
            self.Job = Job
        def __repr__(self):
            return "Person({}, {}, {})".format(self.Name, self.Location, self.Job)
        def __eq__(self, other):
            return self.Name == other.Name and self.Location == other.Location and self.Job == other.Job
         def __hash__(self):
             return hash(repr(self))
    

    然后这样做:

    >>> from operator import itemgetter
    >>> from itertools import product
    >>> data
    [Person(Bob, Salem, Programmer), Person(Steve, New York, Sales), Person(Jeff, New York, Programmer)]
    >>> filter_dictionary = {"Name": [], "Job": ["Programmer"], "Location": ["Salem", "New York"]}
    >>> fd = {key: (value or [getattr(person, key) for person in data]) for key, value in filter_dictionary.items()}
    >>> fd
    {'Job': ['Programmer'], 'Location': ['Salem', 'New York'], 'Name': ['Bob', 'Steve', 'Jeff']}
    >>> items = list(fd.iteritems())
    >>> new = []
    >>> for p in product(*map(itemgetter(1), items)):
            temp = {}
            for index, value in enumerate(p):
                temp[items[index][0]] = value
            new.append(temp)
    
    >>> new
    [{'Job': 'Programmer', 'Location': 'Salem', 'Name': 'Bob'}, {'Job': 'Programmer', 'Location': 'Salem', 'Name': 'Steve'}, {'Job': 'Programmer', 'Location': 'Salem', 'Name': 'Jeff'}, {'Job': 'Programmer', 'Location': 'New York', 'Name': 'Bob'}, {'Job': 'Programmer', 'Location': 'New York', 'Name': 'Steve'}, {'Job': 'Programmer', 'Location': 'New York', 'Name': 'Jeff'}]
    >>> possible_matches = {Person(**kwargs) for kwargs in new}
    >>> ts & set(data)
    {Person(Bob, Salem, Programmer), Person(Jeff, New York, Programmer)}
    

    如您所见,这更长,更麻烦。我不会推荐它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-01
      • 2017-06-14
      • 2014-08-14
      相关资源
      最近更新 更多