如何有效检查元素是否在python中的列表列表中

时间:2019-11-12 22:09:55

标签: python

我有一个列表列表,如下所示。

mylist = [[5274919, ["report", "porcelain", "firing", "technic"]], [5274920, ["implantology", "dentistry"]], [52749, ["method", "recognition", "long", "standing", "root", "perforation", "molar"]], [5274923, ["exogenic", "endogenic", "cause", "tooth", "jaw", "anomaly", "method", "method", "standing"]]]

我还有以下概念列表。

myconcepts = ["method", "standing"]

我想看看myconcepts中的每个概念在mylist记录中有多少次。即;

"method" = 2 times in records (i.e. in `52749` and `5274923`)
"standing" = 2 times in records

我当前的代码如下。

mycounting = 0
for concept in myconcepts:
  for item in mylist:
     if concept in item[1]:
       mycounting = mycounting + 1
print(mycounting)

但是,我目前的mylist非常大,大约有500万条记录。 myconcepts列表包含大约10000个概念。

在我当前的代码中,一个概念花了将近1分钟的时间才能获得count,这很慢。

我想知道在python中最有效的方法吗?

出于测试目的,我将数据集的一小部分附加到了https://drive.google.com/file/d/1z6FsBtLyDZClod9hK8nK4syivZToa7ps/view?usp=sharing

很高兴在需要时提供更多详细信息。

3 个答案:

答案 0 :(得分:2)

您可以展平输入,然后使用collections.Counter

import collections
myconcepts = ["method", "standing"]
mylist = [[5274919, ["report", "porcelain", "firing", "technic"]], [5274920, ["implantology", "dentistry"]], [5274921, ["method", "recognition", "long", "standing", "root", "perforation", "molar"]], [5274923, ["exogenic", "endogenic", "cause", "tooth", "jaw", "anomaly", "method", "standing"]]]
def flatten(d):
  for i in d:
    yield from [i] if not isinstance(i, list) else flatten(i)

r = collections.Counter(flatten(mylist))
result = {i:r.get(i, 0) for i in myconcepts}

输出:

{'method': 2, 'standing': 2}

编辑:记录查找:

result = {i:sum(i in b for _, b in mylist) for i in myconcepts}

输出:

{'method': 2, 'standing': 2}

答案 1 :(得分:2)

https://www.geeksforgeeks.org/python-count-the-sublists-containing-given-element-in-a-list/的适应方法3

from itertools import chain 
from collections import Counter 

mylist = [[5274919, ["report", "porcelain", "firing", "technic"]], [5274920, ["implantology", "dentistry"]], [52749, ["method", "recognition", "long", "standing", "root", "perforation", "molar"]], [5274923, ["exogenic", "endogenic", "cause", "tooth", "jaw", "anomaly", "method", "method", "standing"]]]

myconcepts = ["method", "standing"]

def countList(lst, x):
" Counts number of times item x appears in sublists "
    return Counter(chain.from_iterable(set(i[1]) for i in lst))[x] 

# Use dictionary comprehension to apply countList to concept list
result = {x:countList(mylist, x) for x in myconcepts}
print(result) # {'method':2, 'standing':2}

*修订后的当前方法(仅计算一次)*

def count_occurences(lst):
    " Number of counts of each item in all sublists "
    return Counter(chain.from_iterable(set(i[1]) for i in lst))

cnts = count_occurences(mylist)
result = {x:cnts[x] for x in myconcepts}
print(result) # {'method':2, 'standing':2}

性能(使用Jupyter Notebook比较发布的方法)

结果显示此方法与Barmar发布的方法很接近(即36 vs 42 us)

对当前方法的改进将时间减少了大约一半(即从36 us减少到19 us)。对于更多的概念(即问题中有1000个以上的概念),这种改进应该更加重要。

但是,原始方法的速度更快,为2.55 us / loop。

方法当前方法

%timeit { x:countList(mylist, x) for x in myconcepts}
#10000 loops, best of 3: 36.6 µs per loop

Revised current method:

%%timeit
cnts = count_occurences(mylist)
result = {x:cnts[x] for x in myconcepts}
10000 loops, best of 3: 19.4 µs per loop

方法2(来自Barmar帖子)

%%timeit
r = collections.Counter(flatten(mylist))
{i:r.get(i, 0) for i in myconcepts}
# 10000 loops, best of 3: 42.7 µs per loop

方法3(原始方法)

%%timeit

result = {}
for concept in myconcepts:
  mycounting = 0
  for item in mylist:
     if concept in item[1]:
       mycounting = mycounting + 1
  result[concept] = mycounting
  # 100000 loops, best of 3: 2.55 µs per loop

答案 2 :(得分:1)

将概念列表更改为集合,以便搜索将为O(1)。然后,您可以使用交集来计算每组中的匹配项数。

import set
mylist = [
    [5274919, {"report", "porcelain", "firing", "technic"}], 
    [5274920, {"implantology", "dentistry"}], 
    [52749, {"method", "recognition", "long", "standing", "root", "perforation", "molar"}], 
    [5274923, {"exogenic", "endogenic", "cause", "tooth", "jaw", "anomaly", "method", "method", "standing"}]
]
myconcepts = {"method", "standing"}
mycounting = 0
for item in mylist:
    mycounting += len(set.intersection(myconcepts, item[1]))
print(mycounting)

如果要分别获取每个概念的计数,则需要循环myconcept,然后使用in运算符。您可以将结果放入字典中。

mycounting = {concept: sum(1 for l in mylist if concept in l[1]) for concept in myconcepts}
print(mycounting) // {'standing': 2, 'method': 2}

因为concept in l[1]是O(1),所以它仍然比使用列表更有效。