提问人:Summer 提问时间:11/2/2023 最后编辑:Summer 更新时间:11/4/2023 访问量:130
如何根据索引值在python中过滤列表?
How to filter list in python based on index value?
问:
假设我有 2 个列表,记录了每个人每天吃的苹果数量:
people = ['乔治', '乔治', '乔治', '达纳', '约翰', '约翰']
apples_eaten = [5, 1, 3, 4, 3, 3]
在此方案中,我们有来自 George 的 3 天数据、来自 Dana 的 1 天数据和来自 John 的 2 天数据。
我想知道是否有代码可以根据“人员”列表过滤数据,以便我可以将 George 的数据与输出 [5, 1, 3] 一起拉取。
我想知道如果我以矩阵格式获得这些数据,每个数据集都是一行,以便索引排列,是否有办法更容易做到这一点?我正在从 csv 文件中提取这些列表,但我想知道我是否应该从 csv 文件中提取整个数据集作为矩阵。
专门寻找没有循环的代码,因为我可以很容易地用循环来编码它,但我只是想避免它,因为我的数据集很大,而且我的代码中已经有几个循环,所以我正在努力使它尽可能高效。
编辑: 我想最小化循环的原因是因为我有 4000 个“人”需要排序,比如说数字 1-4000,我需要将这些人映射到大约 11,000 个数据点。
我想到的循环是这样的:
unique_list = [] # list of people with unique IDs numbered 1-4000
people = [] # list of 11,000 repeated ID numbers matching up with data points
data = [] # list of 11,000 data points
for i in len(unique_list)
data_sorted = []
ID = unique_list[i]
for x in len(data)
if people[x] = ID
data_sorted.append(data[x])
else
所以我想避免这种情况的原因是,以我拥有的数据量,这将需要很长时间,而且我不认为这是最有效的代码。让我知道你们的想法,谢谢!
答:
“没有循环”在这里是一个荒谬的条件。当数据没有可利用的结构时,循环是不可避免的。唯一理智的方法是使用循环;循环的少数替代方案将不得不通过额外的步骤完成所有相同的工作,可能以效率较低的方式完成。如果您没有看到循环,那是因为该循环隐藏在为您循环的 API 后面。
撇开这一点不谈,单个查找的解决方案是 listcomp over:zip
people = ['George', 'George', 'George', 'Dana', 'John', 'John']
apples_eaten = [5, 1, 3, 4, 3, 3]
person_data = [cnt for person, cnt in zip(people, apples_eaten) if person == 'George']
就是这样。有一个循环。它是 listcomp 的一部分,由 CPython 进行了大量优化。 本身也针对这种情况进行了大量优化(当它产生的每次都拆包时,它会重用相同的内容,因此不会发生分配)。在任何大小的数据中一次查找单个人都可以,但是您将为查找的每个人执行工作,因此,如果您需要查找多个人或数据中的所有人,则无法很好地扩展。zip
tuple
tuple
O(n)
如果您可能需要查找多个人,并且数据很少更改,则可以预先执行一些工作,以使每个单独的查找成本更低。最简单的解决方案是将每个人映射到他们的相关数据,例如:dict
list
from collections import defaultdict # At top of file
person_to_eaten_count = defaultdict(list)
for person, cnt in zip(people, apples_eaten):
person_to_eaten_count[person].append(cnt)
# Optionally convert back to plain `dict` to prevent future autovivification of keys
person_to_eaten_count = dict(person_to_eaten_count)
一旦你做到了这一点(成本并不比搜索一个人的数据高多少;它是为了构建 ,只是常数因子略高),为任何人查找数据就变得非常便宜; 将获取工作数据,您也可以为任何其他人做同样的事情。dict
O(n)
dict
person_to_eaten_count['George']
George
O(1)
它是这样的:
people = ['George', 'George', 'George', 'Dana', 'John', 'John']
apples_eaten = [5, 1, 3, 4, 3, 3]
dict1={}
i=0
for p in people:
if p in dict1.keys():
dict1[p].append(int(apples_eaten[i]))
else:
dict1[p]=list([])
dict1[p].append(int(apples_eaten[i]))
i+=1
print(dict1)
输出:
{'George': [5, 1, 3], 'Dana': [4], 'John': [3, 3]}
如果人名始终是连续且唯一的,则可以使用 groupby 函数从源列表中构建字典:
people = ['George', 'George', 'George', 'Dana', 'John', 'John']
apples_eaten = [5, 1, 3, 4, 3, 3]
from itertools import groupby
iPeople = iter(people)
data_sorted = {p:g for p,(*g,) in
groupby(apples_eaten,key=lambda _:next(iPeople))}
print(data_sorted)
{'George': [5, 1, 3], 'Dana': [4], 'John': [3, 3]}
如果名称不一定是连续的,则可以使用字典更新按名称组织结果:
data_sorted = dict()
data_sorted.update( (p,data_sorted.get(p,[])+[a])
for p,a in zip(people,apples_eaten) )
print(data_sorted)
[('George', [5, 1, 3]), ('Dana', [4]), ('John', [3, 3])]
评论