我想知道是否有更多的pythonic方法可以从列表中获取一个知道开始和结束值的区间,同时只遍历列表一次。
我想要的不是非常pythonic的方式的例子(存储'Ann'和'John'之间的所有名字):
all_names = []
start_adding = False
for name in names:
if name == 'Ann':
start_adding = True
if start_adding:
all_names.append(name)
if name == 'John':
break
答案 0 :(得分:4)
该解决方案仅遍历列表一次。它只使用标准库中的一个表达式和函数! :)
import itertools as it
l = ['Bill', 'Patrick', 'Aaron', 'Ann',
'Jane', 'Rachel', 'Beatrix',
'John', 'Basil', 'Alice', ]
l = iter(l)
print(
list(
it.chain(
it.dropwhile(lambda _: True, iter(lambda: next(l), 'Ann')),
iter(lambda: next(l), 'John')
)
)
)
输出:
['Jane', 'Rachel', 'Beatrix']
另外 - 演示:http://ideone.com/eOLG6o
答案 1 :(得分:3)
我不知道Pythonic,但是这里只有一次遍历列表并生成中间值的生成器。
def get_between(names, first, last):
f = l = False
for n in names:
l = l or n == last
if f and not l:
yield n
f = f or n == first
它只是采用天真的方法来记住它是否已经看到了你感兴趣的名字和姓氏,并且在看到第一个和最后一个没有时返回值。您可以添加一些早期退出以使其更好。
以下是演示:http://ideone.com/ovnMX2
答案 2 :(得分:2)
这里有点冗长,但更多的pythonic(理论上,更高效)方式:generators and yield
def between_generator(list, start, end):
yield_item = False
for item in list:
if item == start:
yield_item = True
if yield_item:
yield item
if item == end:
break # or raise StopIteration
# usage
for item in between_generator(list, start, end):
print item
# converting to list for multiple use
items = list(between_generator(list, start, end))
这基本上会在列表上方创建一个轻量级单向游标。对其进行迭代将产生start
和end
之间的所有项目。为了多次使用过滤结果,可以将它们输入list
构造函数以创建新列表。
您可能需要咨询question about generators here, on SO以获取更多解释。
答案 3 :(得分:1)
是的; - )
使用index
函数(docs)
r = range(10)
start = r.index(3)
end = r.index(7)
sub_list = r[start:end]
print sub_list
# [3, 4, 5, 6]
# if you want to include the start and end values
sub_list2 = r[start-1:end+1]
print sub_list2
# [2, 3, 4, 5, 6, 7]
答案 4 :(得分:1)
这更紧凑,我觉得它更具可读性
>>> x = ['abc', 'ann', 'elsa', 'silva', 'john', 'carlos', 'michel']
>>> x[x.index('ann'): x.index('john') + 1]
['ann', 'elsa', 'silva', 'john']
答案 5 :(得分:1)
您可以执行类似
的操作read
这看起来并不好看,但应该避免双遍历(假设切片操作不会复制)。
编辑:OP注意到必须扩充索引位置以适合子切片。