The recursive Python function exceeds the recursion limit. How can I convert it to iteration

I created a function that reads lists of ID pairs (ie [("A", "B"), ("B", "C"), ("C", "D"), ...] and sequentially performs identification from beginning to end, including any branches.

Each list of ordered identifier is stored in a class called Alignment, and this function uses recursion to process branches, creating a new alignment, starting with the identifier in which the branch is split from the main list.

I found that with certain inputs, you can reach the maximum recursion limit set by Python. I know that I can simply increase this limit using sys.setrecursionlimit (), but since I do not know how many combinations of branches are possible, I would like to avoid this tactic.

I read several articles about converting recursive functions to iterative functions, but I could not determine the best way to deal with this particular function, because recursion occurs in the middle of the function and can be exponential.

Can any of you suggest any suggestions?

Thanks Brian

The code is below:

def buildAlignments(alignment, alignmentList, endIDs):
    while alignment.start in endIDs:

        #If endID only has one preceding ID: add preceding ID to alignment
        if len(endIDs[alignment.start]) == 1:
            alignment.add(endIDs[alignment.start][0])

        else:

            #List to hold all branches that end at spanEnd
            branches = []

            for each in endIDs[alignment.start]:

                #New alignment for each branch
                al = Alignment(each)

                #Recursively process each new alignment
                buildAlignments(al, branches, endIDs)

                branches.append(al)
            count = len(branches)
            i = 0
            index = 0

            #Loop through branches by length
            for branch in branches:
                if i < count - 1:

                    #Create copy of original alignment and add branch to alignment
                    al = Alignment(alignment)
                    al += branch #branches[index]
                    alignmentList.append(al)
                    i += 1

                #Add single branch to existing original alignment
                else: alignment += branch #branches[index]
                index += 1

def main():
    IDs = [("L", "G"), ("A", "B"), ("B", "I"), ("B", "H"), ("B", "C"), ("F", "G"), ("D", "E"), ("D", "J"), ("E", "L"), ("C", "D"), ("E", "F"), ("J", "K")]

    #Gather all startIDs with corresponding endIDs and vice versa
    startIDs = {}
    endIDs = {}
    for pair in IDs:
        if not pair[0] in startIDs: startIDs[pair[0]] = []
        startIDs[pair[0]].append(pair[1])
        if not pair[1] in endIDs: endIDs[pair[1]] = []
        endIDs[pair[1]].append(pair[0])

    #Create Alignment objects from any endID that does not start another pair (i.e. final ID in sequence)
    alignments = [Alignment(end) for end in endIDs if not end in startIDs]

    #Build build sequences in each original Alignment
    i = len(alignments)
    while i:
        buildAlignments(alignments[i-1], alignments, endIDs)
        i -= 1

EDIT: , - , . , .

: . . , . :

from collections import defaultdict

def expand(line, have_successors, known):
    #print line
    known.append(line)
    for child in have_successors[line[-1]]:
        newline = line + [child]
        if line in known: known.remove(line)
        yield expand(newline, have_successors, known)

def trampoline(generator):
    stack = [generator]
    while stack:
        try:
            generator = stack.pop()
            child = next(generator)
            stack.append(generator)
            stack.append(child)
        except StopIteration:
            pass

def main(pairs):
    have_successors = defaultdict(lambda: set())
    links = set()
    for (start, end) in pairs:
        links.add(end)
        have_successors[start].add(end)
    known = []
    for node in set(have_successors.keys()):
        if node not in links:
            trampoline(expand([node], have_successors, known))
    for line in known:
        print line

if __name__ == '__main__':
    main([("L", "G"), ("A", "B"), ("B", "I"), ("B", "H"), ("B", "C"), ("F", "G"), ("D", "E"), ("D", "J"), ("E", "L"), ("C", "D"), ("E", "F"), ("J", "K")])

: swapped links has_successors if line in known: known.remove(line) , , ID.

UPDATE: , , , , , . , , , . - .

+5
1

. , . ( , ), , , .

, - , :

from collections import defaultdict

def expand(line, links, known):
    print 'expand'
    known.append(line)
    for child in links[line[-1]]:
        newline = line + child
        yield expand(newline, links, known)

def trampoline(generator):
    stack = [generator]
    while stack:
        try:
            generator = stack.pop()
            print 'next'
            child = next(generator)
            stack.append(generator)
            stack.append(child)
        except StopIteration:
            pass

def main(pairs):
    have_successors = set()
    links = defaultdict(lambda: set())
    for (start, end) in pairs:
        have_successors.add(start)
        links[end].add(start)
    known = []
    for node in set(links.keys()):
        if node not in have_successors:
            trampoline(expand(node, links, known))
    for line in known:
        print line

if __name__ == '__main__':
    main([("L", "G"), ("A", "B"), ("B", "I"), ("B", "H"), ("B", "C"), ("F", "G"), ("D", "E"), ("D", "J"), ("E", "L"), ("C", "D"), ("E", "F"), ("J", "K")])

python2.7 - next(foo) foo.__next__() .


-, -, (), . , "" . , ...

-, "", defaultdict, / "". , defaultdict - .

, , , :

  • , , . " ", . ( , ), ( ?). , , . , , "" . , " ", , " , ...", "" .

  • , . - . . ? . , , ? "startIDs" ? " ". , .

  • . startIDs, ? , , . , , ( !: o). : -, , , - . , , , , .

  • , . i index count. ? - , . . if i < count - 1: : " "? , if branch == branches [-1]:, , .

  • . i . , for each alignment in alignments. , , : for each alignment in list(alignments).

  • , . buildAlignment . ? ? , , , . , "", . .

, - . , , , , . , . , , , , ...


[i , newline print .]

-, ? , ? , , ? my expand buildAlignment ().

( ), :

: python2.7 recurse.py
next
expand
next
expand
next
expand
next
expand
next
expand
next
expand
next
expand
next
next
...

, . "" - yield - python .

- . ( , expand), " ", . next(), , yield.

trampoline . next(). "" . next , yield, . trampoline() , next(), ... .. ..

"", StopIteration. , , , trampoline(). "" ( stack) next(). , ( yield), , , while, yield ( StopIteration).

, yield ! , . . , ! , ""! ( stack) - , .

, , , . , . google " ". , . , , , .


, , . , , , , , . ? A- > B, B- > C, C- > A,....

+14

All Articles