【问题标题】:Filtering a list based on a second list根据第二个列表过滤列表
【发布时间】:2012-08-07 04:55:27
【问题描述】:

这可能是一个简单的问题,但我自己无法找到直接的答案。

给定两个列表,一个只有一个 id 列表,另一个包含所有数据,包括一些我们不关心的 id:
all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
ids = ['abc', 'fgh']

获得以下输出的最佳方法是什么,请注意它只保留那些具有相同 id 的输出: new_data = [['abc', 123], ['fgh', 345]]

我当前的代码是这样的:

for x in all_data:
    for y in ids:
         if x[0] == y:
              new_data.append(x)

你会做什么不同的事情?是否有一个内置函数可以解决我在某处遗漏的问题?

(我说“类似”是因为它实际上是一个非常长的序列,涉及集合和所有这一切,这就是为什么没有“pythonic”单行来共享的原因。)

更新: 好吧,你们很有趣。

我让它变得更难一点如何。如果我有一个字典 all_data_dict 而不是“all_data”,它有几个与“all_data”格式相同的列表条目怎么办?按照规则,我会确保接受原始问题的答案,但如果你们都想跟上乐趣,让我们看看我们得到了什么!

【问题讨论】:

    标签: python filter list-comprehension


    【解决方案1】:

    您的第二个问题并不难,只是从头开始构建数据的正确方法:

    >>> all_data = {'abc': 123, 'cde': 234,'fgh': 345}  # a dict
    >>> ids = {'abc', 'fgh'}  # a set
    >>> {k:v for k,v in all_data.viewitems() if k in ids}
    {'abc': 123, 'fgh': 345}
    

    顺便说一句,获取匹配键的一个不错的快速方法是:

    >>> all_data.viewkeys() & ids 
    set(['abc', 'fgh'])
    

    【讨论】:

      【解决方案2】:

      由于很多人使用过 dicts 或 LC,我想我应该显示 filter

      >>> all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]    
      >>> ids = set(['abc', 'fgh'])
      >>> values = filter(lambda value: value[0] in ids, all_data)
      >>> values
      [['abc', 123], ['fgh', 345]]
      >>> 
      

      至于第二部分。

      >>> all_data_dict = {'abc':all_data, 'cde':all_data, 'fgh':all_data}
      >>> ids = set(['abc', 'fgh'])
      >>> dict(filter(lambda value: value[0] in ids, all_data_dict.items()))
      {'abc': [['abc', 123], ['cde', 234], ['fgh', 345]], 'fgh': [['abc', 123], ['cde', 234], ['fgh', 345]]}
      

      【讨论】:

      • 您可以直接使用inlambda value: value[0] in ids
      • 不考虑效率,这是我最喜欢的答案:filter 是自我记录的,您只需阅读该行一次即可了解程序员想要做什么(即过滤)。
      • 是的,我认为它非常有效,因为我们没有创建任何 dicts 检查是恒定的,过滤器应用线性搜索。
      • 是的,我同意它非常有效。我的意思是,即使效率不重要(小集合等),它仍然是我的最爱——单词比构造好,构造比循环好。
      • 绝对选择使用过滤器作为“内置”是我正在寻找的。另外,没有 for 循环。
      【解决方案3】:

      在评论后编辑,我的意思是使用一套。 正如雷蒙德在他的回答中建议的那样,使用带有一组 ID 的列表理解:)。

      all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
      ids = set(['abc', 'fgh'])
      filtered_data = [x for x in all_data if x[0] in ids]
      

      【讨论】:

        【解决方案4】:

        你应该把all_data 变成一本字典,因为你像字典一样使用它:

        d = dict(all_data)
        new_data = [(k, d[k]) for k in ids]
        

        这将使用ids 给出的顺序,而不是all_data 给出的顺序。

        【讨论】:

        • 也许顺序对他很重要?
        • @sblom:这可能很重要,尽管在这种情况下不清楚是使用all_data 的顺序还是ids 的顺序。 (另请注意,您的意思可能是“对很重要”。)
        • 绝对是。对不起,@Lillian!
        【解决方案5】:

        使用列表推导式,其中条件检查集合中的成员:

        >>> all_data = [['abc', 123], ['cde', 234], ['fgh', 345]]
        >>> ids = ['abc', 'fgh']
        >>> id_set = set(ids)
        >>> [s for s in all_data if s[0] in id_set]
        [['abc', 123], ['fgh', 345]]
        

        【讨论】:

        • 如果我的答案和你雷蒙德一样,那就意味着我一定做对了:)
        • @anijhaw:不,你的答案是 O(m·n),而 Raymond 的答案是 O(n)。
        • 我本来打算用一套我觉得我很胖但谢谢你的指正。
        猜你喜欢
        • 2021-08-19
        • 2021-07-25
        • 2018-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-17
        • 1970-01-01
        相关资源
        最近更新 更多