在python中对列表进行分类的最佳方法是什么?
例如:
totalist is below
totalist[1] = ['A','B','C','D','E']
totalist[2] = ['A','B','X','Y','Z']
totalist[3] = ['A','F','T','U','V']
totalist[4] = ['A','F','M','N','O']
假设我想获取前两个项['A','B']
的列表,基本上是list[1]
和list[2]
。有没有一种简单的方法来获得这些,而不是一次迭代一个项目?像这样的东西?
if ['A','B'] in totalist
我知道这不起作用。
答案 0 :(得分:3)
您可以查看每个列表的前两个元素。
for totalist in all_lists:
if totalist[:2] == ['A', 'B']:
# Do something.
注意: Kasramvd建议的单线解决方案也很不错。我发现我的解决方案更具可读性虽然我应该说理解比循环的常规要快一些。 (我自己测试过。)
答案 1 :(得分:2)
只是为了好玩,itertools
解决方案将每个元素的工作推送到C层:
from future_builtins import map # Py2 only; not needed on Py3
from itertools import compress
from operator import itemgetter
# Generator
prefixes = map(itemgetter(slice(2)), totalist)
selectors = map(['A','B'].__eq__, prefixes)
# If you need them one at a time, just skip list wrapping and iterate
# compress output directly
matches = list(compress(totalist, selectors))
这可能都是一线的:
matches = list(compress(totalist, map(['A','B'].__eq__, map(itemgetter(slice(2)), totalist))))
但我不推荐它。顺便提一下,如果totalist
可能是生成器而不是可重复序列,那么您需要使用itertools.tee
将其加倍,并添加:
totalist, forselection = itertools.tee(totalist, 2)
并将prefixes
的定义更改为map
而不是forselection
,而不是totalist
;由于compress
并行迭代两个迭代器,tee
将没有有意义的内存开销。
当然,正如其他人所说,即使转向C,这也是一种线性算法。理想情况下,您可以使用collections.defaultdict(list)
之类的内容从每个list
的两个元素前缀(转换为tuple
以使其成为合法dict
键)映射到{{带有该前缀的所有list
的1}}。然后,代替对N list
进行线性搜索以找到具有匹配前缀的那些,您只需执行list
并获得totaldict['A', 'B']
查找的结果(并且修复工作也较少;没有常数切片)。
预计算工作示例:
O(1)
然后,您可以立即有效地获取from collections import defaultdict
totaldict = defaultdict(list)
for x in totalist:
totaldict[tuple(x[:2])].append(x)
# Optionally, to prevent autovivification later:
totaldict = dict(totaldict)
任意两个元素前缀:
matches
答案 2 :(得分:1)
基本上你不能在嵌套列表的python中做到这一点。但是,如果您正在寻找一种优化的方法,可以采用以下方法:
使用简单的列表理解,通过将预期列表与前两个子列表项进行比较:
>>> [sub for sub in totalist if sub[:2] == ['A', 'B']]
[['A', 'B', 'C', 'D', 'E'], ['A', 'B', 'X', 'Y', 'Z']]
如果您希望索引使用enumerate
:
>>> [ind for ind, sub in enumerate(totalist) if sub[:2] == ['A', 'B']]
[0, 1]
这是Numpy中的一种方法,当您处理大型数据集时,它已经过几乎优化:
>>> import numpy as np
>>>
>>> totalist = np.array([['A','B','C','D','E'],
... ['A','B','X','Y','Z'],
... ['A','F','T','U','V'],
... ['A','F','M','N','O']])
>>> totalist[(totalist[:,:2]==['A', 'B']).all(axis=1)]
array([['A', 'B', 'C', 'D', 'E'],
['A', 'B', 'X', 'Y', 'Z']],
dtype='|S1')
如果你不想使用循环并且你正在寻找一种功能方式,那么作为python中列表理解的替代方法,你可以使用filter
函数,它不像列表理解那样优化:
>>> list(filter(lambda x: x[:2]==['A', 'B'], totalist))
[['A', 'B', 'C', 'D', 'E'], ['A', 'B', 'X', 'Y', 'Z']]
答案 3 :(得分:1)
你可以这样做。
>>> for i in totalist:
... if ['A','B']==i[:2]:
... print i
答案 4 :(得分:0)
您暗示您关注性能(成本)。如果您需要这样做,并且如果您担心性能,则需要不同的数据结构。这将增加一点成本"制作列表时,但在过滤时节省时间。
如果需要根据前两个元素进行过滤是固定的(它不会推广到前n个元素)那么我会将这些列表添加到一个字典中,其中键是一个前两个元素的元组,该项是列表列表。
然后您只需通过执行dict查找来检索列表。这很容易做到并且会带来潜在的大加速,在制作列表时几乎不需要内存和时间。