【问题标题】:Search a list of list of strings for a list of strings in python efficiently在python中有效地搜索字符串列表以获取字符串列表
【发布时间】:2012-02-16 18:31:06
【问题描述】:

我有一个字符串列表和一个字符串列表。例如:

L1=[["cat","dog","apple"],["orange","green","red"]]
L2=["cat","red"]

如果 L1[i] 包含 L2 中的任何项目,我需要放置对(用于在图中创建边) 比如,在我的例子中,我需要("cat","dog"),("cat,apple"),("red,orange"),("red","green")

我应该使用什么方法来使其最有效。 (我的 L1 列表很大)

【问题讨论】:

  • 您是否直接尝试过(可能效率较低)?

标签: python list


【解决方案1】:

假设您的 L1 子列表中可能有多个“控制”项。

我会使用set()itertools.product()

from itertools import product

def generate_edges(iterable, control):
    edges = []
    control_set = set(control)
    for e in iterable:
        e_set = set(e)
        common = e_set & control_set
        to_pair = e_set - common
        edges.extend(product(to_pair, common))
    return edges

例子:

>>> L1 = [["cat","dog","apple"],
...       ["orange","green","red"],
...       ["hand","cat","red"]]
>>> L2 = ["cat","red"]
>>> generate_edges(L1, L2)
[('apple', 'cat'),
 ('dog', 'cat'),
 ('orange', 'red'),
 ('green', 'red'),
 ('hand', 'red'),
 ('hand', 'cat')]

【讨论】:

    【解决方案2】:

    我建议将它们全部转换为sets 并使用集合运算(交集)来确定每个 L1 项目中来自 L2 的哪些术语。然后,您可以使用集合减法来获取需要配对的项目列表。

    edges = []
    L2set = set(L2)
    for L1item in L1:
        L1set = set(L1item)
        items_in_L1item = L1set & L2set
        for item in items_in_L1item:
            items_to_pair = L1set - set([item])
            edges.extend((item, i) for i in items_to_pair)
    

    【讨论】:

      【解决方案3】:

      即使L1L2 很大,要使此代码优化,请使用izip 生成生成器,而不是创建庞大的元组列表。如果您使用的是 Python3,请使用 zip

      from itertools import izip
      
      pairs = []
      for my_list, elem in izip(L1, L2):
          if elem in my_list:
              pairs += [(elem, e) for e in my_list if e!=elem]
      print pairs
      

      代码很通俗易懂,几乎是纯英文的!首先,您循环遍历每个列表及其对应的元素,然后询问该元素是否在列表中,如果是,则打印除 (x, x) 对之外的所有对。

      输出:

      [('cat', 'dog'), ('cat', 'apple'), ('red', 'orange'), ('red', 'green')]
      

      【讨论】:

      • 您的代码不适用于 OP 正在寻找的一般情况。
      • 因为 L2 中的任何元素都可能在 L1 中的任何列表中,并且 L1 中的列表数量可能与 L2 中的元素数量不同。
      【解决方案4】:

      如果 L1 非常大,您可能需要考虑使用 bisect。它要求先对 L1 进行展平和排序。你可以这样做:

      from bisect import bisect_left, bisect_right
      from itertools import chain
      
      L1=[["cat","dog","apple"],["orange","green","red","apple"]]
      L2=["apple", "cat","red"]
      
      M1 = [[i]*len(j) for i, j in enumerate(L1)]
      M1 = list(chain(*M1))
      L1flat = list(chain(*L1))
      I = sorted(range(len(L1flat)), key=L1flat.__getitem__)
      L1flat = [L1flat[i] for i in I]
      M1 = [M1[i] for i in I]
      
      for item in L2:
          s = bisect_left(L1flat, item)
          e = bisect_right(L1flat, item)
          print item, M1[s:e]
      
      #apple [0, 1]
      #cat [0]
      #red [1]
      

      【讨论】:

        猜你喜欢
        • 2019-06-26
        • 2020-03-12
        • 2012-01-29
        • 1970-01-01
        • 1970-01-01
        • 2016-04-21
        • 1970-01-01
        • 2019-05-29
        • 2014-08-30
        相关资源
        最近更新 更多