web-dev-qa-db-ja.com

再帰関数でカウントを維持する方法は?

親文字列内の部分文字列のインスタンスの数を見つけるための再帰関数を作成しました。

私がカウントを維持する方法は、countを関数のスコープ外のグローバル変数として宣言/初期化することです。問題は、関数が最初に実行されたときにのみ正しい結果が得られることです。それ以降はcount != 0そもそも。そして、関数内にある場合、再帰的に呼び出されるたびに、0に設定されます。

count=0
def countSubStringMatchRecursive(target,key):
    index=find(target,key)
    global count
    targetstring=target
    if index>=0:
        count=count+1
        target=target[index+len(key):]
        countSubStringMatchRecursive(target,key)
    else :
        pass
    return "No. of instances of", key, 'in', targetstring, 'is', count

注:具体的にはrecursive関数の解決策を探しています。これは、正常に機能する反復関数を持っています。

編集:ありがとうございました、これは宿題の一部だったので、私は文字列モジュールのみを使用していました

17
gsin

コードを変更する1つの方法は、次のようにローカル関数を使用することです。

def countSubStringMatchRecursive(target,key):
    def countit(target,key,count):
        index=find(target,key)
        if index>=0:
            target=target[index+len(key):]
            count += countit(target,key,count) + 1
        return count
    return "No. of instances of", key, 'in', target, 'is', countit(target,key,0)
14
Greg Hewgill

再帰関数は、一致するものが見つかるたびに文字列の残りの内容をコピーするため、O(n ^ 2)のパフォーマンスを発揮します。これは反復解O(n)よりも遅く、不必要にそうです。

検索の開始インデックスをオプションのパラメーターとして関数に渡すことで、コードを簡単に書き直して高速化すると同時に、コードを簡素化して機能を拡張できます。

def countSubStringMatchRecursive(target, key, start_index = 0):
    index = target.find(key, start_index)
    if index >= 0:
        return countSubStringMatchRecursive(target, key, index + len(key)) + 1
    return 0

target_string = 'an Apple and a banana'
key = 'an'
count = countSubStringMatchRecursive(target_string,  key)
print "Number of instances of %r in %r is %d" % (key, target_string, count)

出力:

Number of instances of 'an' in 'an Apple and a banana' is 4

更新:文字列モジュールのfind関数を本当に使用したい場合は、1行変更するだけでこれを実行できます。

index = find(target, key, start_index)
9
Mark Byers

これはGregHewgillの答えに似たものです。ただし、代わりに、関数を呼び出すたびに現在のカウントを渡し、一致するものがなくなるとカウントを返します。 Pythonでは違いはないと思いますが、末尾呼び出しの再帰を実装する言語では、これにより、do_countへの連続する各呼び出しを呼び出しスタック上で最適化できます。これは、do_countを呼び出すたびに、呼び出しスタックが大きくなることはないことを意味します。

def count_sub_strings(target, key):
    def do_count(target, key, count):
        index = target.find(key)
        if index >= 0:
            target = target[index + len(key):]
            return do_count(target, key, count + 1)
        else:
            return count
    return "No. of instances of %s in %s is %s" % (key, target, do_count(target, key, 0))
6

補足:提示されたすべての解決策(元のQからすべてのAsまで)は、具体的に述べられたものとは異なる問題を解決しています(これは特定の問題ステートメントのバグだと思いますが、修正する価値があります;-) 。考えてみましょう:

_>>> 'banana'.count('ana')
1
>>> sum('banana'[x:x+3]=='ana' for x in range(len('banana')))
2
_

最初の式は、重複しない「バナナ」内の「ana」の出現をカウントしています。 2つ目は、allの発生をカウントすることです。「バナナ」のインデックス1と3に、全部で2つの発生があり、重複しています。だから問題のステートメントを与えられて、私は引用します:

いいえを見つけます。親文字列内の部分文字列のインスタンスの。

「非重複」についての言及がなければ、重複する発生カウントされるべきであるように思われます。もちろん、これは簡単に修正できます。気づいたら、重複するオカレンスをスキップするlen(key)だけ進むのではなく、毎回1ずつ進める必要があります。

したがって、たとえば:

_import string

def countit(target, key, startfrom=0):
    where = string.find(target, key, startfrom)
    if where < 0: return 0
    return 1 + countit(target, key, where+1)

print countit('banana', 'ana')
_

_2_を出力し、両方の(重複する)発生をカウントします。

6
Alex Martelli

私はOpenCoursewareでこのコースをやっています、それは素晴らしいです。とにかく、これは私がしたことです。私は上記のアダムスからインスピレーションを得ました。

def countSubStringMatchRecursive(target, key, counter = 0):
    if find(target,key) == 0:
        countSubStringMatchRecursive(target[1:], key, counter + 1)
    Elif find(target,key) > 0:
        countSubStringMatchRecursive(target[1:], key, counter)
    Elif find(target,key) == -1:
        print counter
3
tyler

重複するオカレンスを考慮し、 [〜#〜] mit [〜#〜] からの元の定義を維持することは、私が取得できるより単純でコンパクトなコードです。

コード:

from string import *
def countSubStringMatchRecursive(target, key):
    index = find(target, key)
    if index > -1:
        return countSubStringMatchRecursive(target[index + 1:], key) + 1
    return 0


def test(target, key):
    instances = countSubStringMatchRecursive(target, key)
    if instances == 0:
        print "No instance of %r in %r" % (key, target)
    else:
        print "Number of instances of %r in %r: %d" % (key, target, instances)

test("atgacatgcacaagtatgcat","ggcc")
test("atgacatgcacaagtatgcat","atgc")
test("banana", "ana")

出力:

'atgacatgcacaagtatgcat'に 'ggcc'のインスタンスがありません

'atgacatgcacaagtatgcat'内の 'atgc'のインスタンス数:2

「バナナ」の「アナ」のインスタンス数:2

3
Ari Bj Rvnn
def countSubStringMatchRecursive(target, key):
    index = string.find(target, key)
    if index == -1:
        return 0
    else:
        return 1 + countSubStringMatchRecursive(target[index + len(key):], key)
2
leesto

これはどう?

def count_it(target, key):
    index = target.find(key)
    if index >= 0:
        return 1 + count_it(target[index+len(key):], key)
    else:
        return 0


print count_it("aaa bbb aaa ccc aaa", "aaa")

出力:

3
1
Ryan Ginstrom

ない未テスト.。

コード:

_def countSubStringMatchRecursive(target, key, count=0):
    #### index = find(target, key) # HUH?
    index = target.find(key)
    if index >= 0:
        count += 1
        target = target[index+len(key):]
        count = countSubStringMatchRecursive(target, key, count)
    return count

for test in ['', 'bar', 'foo', 'foofoo', 'foo foo foo fo']:
   print countSubStringMatchRecursive(test, 'foo'), test.count(key), repr(test)
_

出力:

_0 0 ''
0 0 'bar'
1 1 'foo'
2 2 'foofoo'
3 3 'foo foo foo fo'
_

これは単なる娯楽または宿題だと思います...再帰関数は対応するPython反復解法よりも遅くなければなりません。これは、target.count(key)を使用するよりも当然遅くなります。 。だから私はあなたのバージョンが持っていたすべての問題を修正することに悩まされていません...しかしPEP-008を読んでください:-)

文字列モジュールに関するコメント

_from string import find_を省略したとコメントしました。どのバージョンのPythonを使用していますか?使用している本またはチュートリアルの最終更新日はいつですか?

文字列モジュールの最初から(コンピュータには_<your Python install directory>/Lib/string.py_として表示されます。2.6バージョンから引用しています):

"" "文字列操作のコレクション(ほとんどは使用されなくなりました)。

警告:ここに表示されるコードのほとんどは、現在は通常使用されていません。 Python 1.6以降、これらの関数の多くは標準の文字列オブジェクトのメソッドとして実装されていました。以前はstropという組み込みモジュールによって実装されていましたが、strop自体は廃止されました。

など "" "

find関数のファイルのコードは次のとおりです(コメントは削除されています)。

_def find(s, *args):
    return s.find(*args)
_

したがって、string.find(target, key)の代わりにtarget.find(key)を使用するのは無駄です。

1
John Machin
steps = 0
def addPersistence(number, steps):
    steps += 1
    if len(str(number))==1:
        print(str(number) + "\nDone---------------------------------------------------")
        print("TOTAL STEPS " + str(steps-1))

    digits = [int(i) for i in str(number)]

    result = 0
    for j in digits:
        result += j


    if len(str(number)) != 1:
        print(number)
        addPersistence(result, steps)

これは私のプロジェクトの1つからコピーした例です。この関数は、数値の永続性の追加(数値の桁を加算し、数値が1になるまで繰り返す)を決定するためのものですが、確実に再利用可能であり、次のように関数を使用できます(これはPython 3コード、Python 2に変更したい場合は、引き続き機能します):

count=0
def countSubStringMatchRecursive(target,key,count):
    index=find(target,key)
    targetstring=target
    if index>=0:
        count+=1
        target=target[index+len(key):]
        countSubStringMatchRecursive(target,key,count)
    else :
        pass
    print("STEPS: "+str(count))

あなたは私のコードに気付くかもしれません、そしてそのコードは少し異なっています。どうして?答えは、その関数を使用して数値が1になるまでにかかるステップ数は、最後の呼び出しがその前の呼び出しの重複であるため、私の関数に含まれないということです。

0
zixuan

もう1つの方法は、元々0に設定されているcountという名前のcountSubStringMatchRecursive関数に3番目のオプションのパラメーターを設定することです。そうすれば、カウントを追跡できます。これにより、count変数が外部に公開されるため、望ましくない場合がありますが、グローバル変数よりも悪くはないため、問題になるとは思いません。

また、コードを変更して、最後の再帰呼び出しを、returnステートメントを外部に与える呼び出しにする必要があります。この例を参照してください(未テスト):

def countSubStringMatchRecursive(target, key, count = 0):
    index = find(target, key)
    targetstring = target
    if index >= 0:
        count += 1
        target = target[index+len(key):]
        countSubStringMatchRecursive(target, key, count)
    else:
        return "No. of instances of", key, 'in', targetstring, 'is', count

編集:元の文字列を再帰に沿って移動させ続けるには、4番目のパラメーターが必要であることに気付きました。これはおそらく最適なソリューションではないため、GregHewgillのソリューションを使用することをお勧めします。外部との相互作用と「ビジネスロジック」が明確に分離されているため、コードがより再利用可能になります。

0
adamse