[英]Collect elements from a list of lists based on the first elements of each group
我有一个清单
mainlist = [['a','online',20],
['a','online',22],
['a','offline',26],
['a','online',28],
['a','offline',31],
['a','online',32],
['a','online',33],
['a','offline',34]]
如果第二个元素是'online'
,而下一个'offline'
值是第四个元素,我想获得第三个元素'offline'
最小值。 迭代应该进行到列表的末尾。
最终输出应为
outputlist = [['a', 'online', 20, 26], ['a', 'online', 28, 31], ['a', 'online', 32, 34]]
我尝试了下面的代码,但没有帮助我:
from itertools import product
for a, b in product(mainlist,mainlist):
if a[1] == 'online':
minvalue=min(a, key=lambda x:x[2])
if b[1] == 'offline' and b[2] >=minvalue[2]:
maxvalue=min(b, key=lambda x:x[2])
好像您正在寻找连续的“在线”连胜纪录
只需从头到尾遍历该列表,并记住“联机”何时开始,然后在下一个“脱机”中将此条纹添加到结果中:
mainlist = [['a', 'online', 20], ['a', 'online', 22], ['a', 'offline', 26], ['a', 'online', 28], ['a', 'offline', 31], ['a', 'online', 32], ['a', 'online', 33], ['a', 'offline', 34]]
output = []
first_online = -1
for item, status, num in mainlist:
if status == 'online':
if first_online == -1:
first_online = num
elif status == 'offline':
output.append([item, 'online', first_online, num])
first_online = -1
print(output)
这是使用iter
一种方法
例如:
mainlist=iter([['a','online',20],['a','online',22],['a','offline',26],['a','online',28],['a','offline',31],['a','online',32],['a','online',33],['a','offline',34]])
result = []
for i in mainlist:
if i[1] == 'online':
result.append(i)
while True:
i = next(mainlist)
if i[1] == "offline":
result[-1].append(i[-1])
break
输出:
[['a', 'online', 20, 26], ['a', 'online', 28, 31], ['a', 'online', 32, 34]]
我们可以用itertools.groupby
到具有相同的第二元素组连续的名单, 'online'
或'offline'
,的帮助下itertools.itemgetter
,然后只收集必要的输出列表:
from itertools import groupby
from operator import itemgetter
mainlist = [['a', 'online', 20],
['a', 'online', 22],
['a', 'offline', 26],
['a', 'online', 28],
['a', 'offline', 31],
['a', 'online', 32],
['a', 'online', 33],
['a', 'offline', 34]]
result = []
for key, group in groupby(mainlist, key=itemgetter(1)):
if key == 'online':
output = min(group, key=itemgetter(2)).copy()
# or `output = next(group).copy()` if data is always sorted
else:
next_offline = next(group)
output.append(next_offline[2])
result.append(output)
print(result)
# [['a', 'online', 20, 26], ['a', 'online', 28, 31], ['a', 'online', 32, 34]]
我发现此版本比此处介绍的其他版本更好,因为代码未深层嵌套且不使用“标志”变量。
进一步改进:
正如Guido van Rossum所说: “ 元组用于异构数据,列表用于异构数据。 ”但是现在,您的列表保留了异构数据。 我建议使用namedtuple
,它可以更轻松地区分字段。 我将使用来自typing
模块的打字版本 ,但您可以自由使用来自collections
。 例如,它可能看起来像这样:
from typing import NamedTuple
class Record(NamedTuple):
process: str
status: str
time: int
class FullRecord(NamedTuple):
process: str
status: str
start: int
end: int
我们可以使用itertools.starmap
从您的列表列表中轻松获取Record
的列表:
from itertools import starmap
records = list(starmap(Record, mainlist))
# [Record(process='a', status='online', time=20),
# Record(process='a', status='online', time=22),
# Record(process='a', status='offline', time=26),
# Record(process='a', status='online', time=28),
# Record(process='a', status='offline', time=31),
# Record(process='a', status='online', time=32),
# Record(process='a', status='online', time=33),
# Record(process='a', status='offline', time=34)]
然后,将第一个代码示例包装在generator函数中 ,并替换其中的某些部分以反映输入数据中的更改:
def collect_times(values):
for key, group in groupby(values, key=Record.status.fget):
if key == 'online':
min_online_record = next(group)
else:
next_offline_record = next(group)
yield FullRecord(process=min_online_record.process,
status='online',
start=min_online_record.time,
end=next_offline_record.time)
result = list(collect_times(records))
# [FullRecord(process='a', status='online', start=20, end=26),
# FullRecord(process='a', status='online', start=28, end=31),
# FullRecord(process='a', status='online', start=32, end=34)]
就是这样,现在的代码看起来比以前更容易解释。 我们可以看到哪个字段在哪里,它们是通过名称而不是索引来引用的。
请注意,在对数据进行排序时,我会写min_online_record = next(group)
,但如果并非总是如此,则应改写min_online_record = min(group, key=Record.time.fget)
。
另外,如果您有兴趣,请注意Record
和FullRecord
的字段重复。 您可以通过从具有两个字段process
和status
的父类继承来避免这种status
,但是从namedtuple
继承并不是一件很漂亮的事情 。 因此,如果这样做,请改用dataclass
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.