2

1または0のいずれかを含むリストがあります。他には何もありません。私は1を見つけることに興味があります。具体的には、1の実行が開始し、その実行が終了する場所(または、以下のコードでは、1の実行の「長さ」....「長さ」のいずれかです。 「その実行の、またはその実行の終了インデックス位置。数学を実行して、開始位置と終了位置からの長さを計算できます)。1の実行をハッシュに格納しています。私が持っているものよりも私が求めているものを手に入れるためのより速い方法はありますか?私はまだPythonを学んでおり、実際に使用しているリストははるかに大きいため、速度が重要です。

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)
4

4 に答える 4

7

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のグループの開始インデックスと終了インデックスが出力されます。

于 2013-03-07T19:49:08.250 に答える
2

@mgilsonのpythonic回答とは別に、次のようなものを試すこともできます。

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
于 2013-03-07T20:10:40.077 に答える
1

これがもう少し効率的な解決策です(申し訳ありませんがJavaScriptです)。重要なのは、長さを1回だけ保存することです。コードでは、長さが1つ増えるたびに計算を行います "startLength [start] = 1 +cnt--start"。

「ifprevious==1 and r == 1」の代わりに、条件「if previous == 0 and r==1」を使用します。計算の量を減らしますが、最後のケースをキャッチするために、forループの後に「ifr==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]);

編集2これは、groupby関数(現在、この質問に対する一番の答え)の使用が大幅に遅いことを示すPythonベンチマークです。

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
于 2013-03-07T20:50:43.793 に答える
-1

リストを文字列に変換する場合は、これに正規表現を使用できます。

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()
于 2013-03-07T19:46:56.250 に答える