Python 如何在列表中查找一系列数字的长度?(有没有比我现在做的更快的方法?)
我有一个包含1或0的列表;没有别的了。我感兴趣的是查找1,更具体地说,查找1的开始位置和结束位置(或者在下面的代码中,查找1的“长度”…它可以是该运行的“长度”,也可以是该运行的结束索引位置,因为我可以做数学运算并计算出从开始和结束位置开始的长度)。 我正在将1的运行存储在散列中。有没有比我所拥有的更快的方法来获得我所追求的?我还在学习python,我在现实生活中使用的列表要多得多,所以速度很重要Python 如何在列表中查找一系列数字的长度?(有没有比我现在做的更快的方法?),python,list,Python,List,我有一个包含1或0的列表;没有别的了。我感兴趣的是查找1,更具体地说,查找1的开始位置和结束位置(或者在下面的代码中,查找1的“长度”…它可以是该运行的“长度”,也可以是该运行的结束索引位置,因为我可以做数学运算并计算出从开始和结束位置开始的长度)。 我正在将1的运行存储在散列中。有没有比我所拥有的更快的方法来获得我所追求的?我还在学习python,我在现实生活中使用的列表要多得多,所以速度很重要 previous = 0 cnt = 0 startLength = {} for r in l
previous = 0
cnt = 0
startLength = {}
for r in listy:
if previous == 0 and r == 1:
start = cnt
startLength[start] = 1
if previous == 1 and r == 1:
startLength[start] = 1 + cnt - start
previous = r
cnt += 1
for s,l in startLength.iteritems():
print "A run of 1's starts at position %s and lasts %s" % (s,l)
如果将列表转换为字符串,则可以使用正则表达式
import re
import random
int_list = [random.randint(0,1) for i in xrange(1000000)]
runs = re.findall('1+', ''.join(map(str, int_list) # get a list of one-runs
# Print their lengths.
for run in runs:
print len(run)
# If you really need to know the indexes where the runs are found, instead use
runs = re.finditer('1+', ''.join(map(str, int_list) # get a list of matches
for run in runs:
print 'Start:\t%s' % run.start()
print 'End:\t%s' % run.end()
print 'Length:\t%s' % run.end()-run.start()
我可能会使用
itertools.groupby
进行此操作
lst = [ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0]
from itertools import groupby
from operator import itemgetter
for k,v in groupby(enumerate(lst),key=itemgetter(1)):
if k:
v = list(v)
print v[0][0],v[-1][0]
这将打印1组的开始和结束索引除了@mgilson的python答案之外,您还可以尝试以下方法:
lst = [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1]
start, end = False, False
for i, x in enumerate(lst):
if x == 1 and start is False:
start = i
if x == 0 and start is not False and end is False:
end = i-1
if start is not False and end is not False:
print start, end # and len is (end-start+1)
start, end = False, False
if start is not False:
print start, i
输出:
0 4
12 15
22 23
这里有一个稍微更有效的解决方案(很抱歉是JavaScript)。关键是只存储一次长度,在代码中,每次长度增加一个“startLength[start]=1+cnt-start”时,都要进行计算 通过使用条件“if-previous==0和r==1”而不是“if-previous==1和r==1”。我减少了计算量,但是我还必须在for循环之后添加一个“if r==1”来捕捉最后的情况
var test=[0,1,1,1,0,0,0,1,1,0,0,1,0];
function runs(arr) {
var result = {};
var start = 0;
var previous = 0;
var cnt = 0;
var r = 0;
for(; cnt<arr.length; cnt++) {
var r = arr[cnt];
if(r == 1 && previous == 0)
start = cnt;
if(r == 0 && previous == 1)
result[start] = cnt - start;
previous = r;
}
if(r == 1)
result[start] = cnt - start;
return result;
}
var result = runs(test);
for(var start in result)
console.log("start " + start + " length " + result[start]);
如果他从一个整数列表开始,他首先必须将每个元素转换为一个字符串,并将它们连接在一起。这并不是我所说的“快”。他也没有试图在没有上下文的情况下获得所有跑步记录的列表,他试图在整个列表的上下文中获得每一次跑步记录。不同意/否决票。它有效。它可以做OP没有要求做的事情…@bernie downvote按钮没有说“这个答案不起作用”,它说“这个答案没有用”。但是仍然比根本不做慢,这更好,因为它没有必要。此外,您仍然没有生成OP要求的值;他想要每次跑步的开始指数(在原始序列内)和长度,而不仅仅是跑步本身的列表,所以你只达到了目标的一部分。一天内重复两次感觉很奇怪,但可能重复我没有看到。我的问题有点不同,但思路是一样的。@Gaga先生-如果速度对您很重要,那么使用链接副本中的答案,特别是groupby功能最终会变慢。thx帮助我们python新手!既然问题是关于“最快”的速度,这似乎是一个非常低效的答案。这显然是最具python风格的答案,但我想这会比OPs实现运行得慢得多。@LastCoder--为什么你会认为这是低效的?
itertools
的目的是高效地执行类似操作。@mgilson-groupby+enumerate+itemgetter的额外开销。仅仅因为它写的更少并不意味着它执行的更快。@mgilson-我用一个快速的基准更新了我的答案,正如我所怀疑的那样,你的版本只需要10000个元素,执行速度就慢了2-3倍。不管库代码有多高效,它仍然必须遍历列表并执行过多的操作。同样,如果你想要快速的东西,它看起来与简单/优雅的东西不同。但既然连OP都同意你的答案,我只能假设他并不真的想要快速的东西,只是python-ish的东西。这不会在序列中捕捉到最后的1。如果“开始”不为False,“结束”不为False,则需要添加:打印开始,在结尾处结束。抱歉,忽略我之前的评论,您需要添加行:这不会捕获序列中最后运行的1。如果开始不为False,则需要添加:打印开始,结尾为i。
from itertools import groupby
from operator import itemgetter
import random
import time
lst = [ 1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0]
def makeList(size):
random.seed()
return [random.randint(0,1) for r in xrange(size)]
def runs1(lst, showOutput):
startLength = {}
for k,v in groupby(enumerate(lst),key=itemgetter(1)):
if k:
v = list(v)
startLength[v[0][0]] = v[-1][0] + 1 - v[0][0]
if showOutput == True:
for s,l in startLength.iteritems():
print s,l
def runs2(lst, showOutput):
previous = 0
cnt = 0
startLength = {}
for r in lst:
if previous == 0 and r == 1:
start = cnt
if previous == 1 and r == 0:
startLength[start] = cnt - start
previous = r
cnt += 1
if r == 1:
startLength[start] = cnt - start
if showOutput == True:
for s,l in startLength.iteritems():
print s,l
testList = makeList(10)
print "slow version"
runs1(testList, True)
print "fast version"
runs2(testList, True)
benchmarkList = makeList(10000)
start = time.time()
runs1(benchmarkList, False)
print "slow ", time.time() - start
start = time.time()
runs2(benchmarkList, False)
print "fast ", time.time() - start
start = time.time()
runs1(benchmarkList, False)
print "slow ", time.time() - start
start = time.time()
runs2(benchmarkList, False)
print "fast ", time.time() - start
start = time.time()
runs1(benchmarkList, False)
print "slow ", time.time() - start
start = time.time()
runs2(benchmarkList, False)
print "fast ", time.time() - start