Skip to content Skip to sidebar Skip to footer

Add An Item Into A List Recursively

Hi. I was wondering if there is a way to add items into a list recursively. The function is supposed to print the path names of the file that matches with fname. So fname is the na

Solution 1:

Normally, I wouldn't give a full solution because this smells like homework (which is also why I'm avoiding os.walk), but since you have posted your attempt, here's an explanation and a solution:

For one thing, every time you call findAll, you initialize lst. Sure, you return it at the end, but you don't do anything with the return value, so the effect lst.append is contained within the recursion and is therefore not visible outside. Let me try to draw diagram to explain this (with one level of recursion):

+--------------------------------------------------+|Outer Level:                                      ||||`lst = []`                                        ||found file f1 with name fname                     ||`lst.append(f1)`                                  ||+------------------------------------------------+|||Inner Level                                     ||||||||`lst=[]`                                        ||||found file f2 with name fname                   ||||`lst.append(f2)`                                ||||`return lst`                                    |||+------------------------------------------------+||a list is returned fromrecursivecall,           ||but not assigned to a variable.                   ||Therefore, `lst` remains unchanged                |+--------------------------------------------------+

There are a couple of ways by which you can fix this:

  1. move lst to a scope outside findAll (personally, this is what I would do)
  2. use the return value from the recursive call to modify lst

move lst to a scope outside findAll

lst= []
deffindAll(fname, path): 
    global lst
    for item in os.listdir(path):
        n = os.path.join(path, item)
        try: # really though, you don't need to use try/except hereif item == fname:
                lst.append(n)
            else:
                findAll(fname,n)
        except:
            pass

After findAll has terminated, lst will contain the values you want

use the return value from the recursive call to modify lst

def findAll(fname, path, answer=None):
    if answer == None:
        answer = []
    for item inos.listdir(path):
        n = os.path.join(path, item)
        try:
            if item == fname:
                answer += [n]
        except:
            findAll(fname,n, answer)
    return answer

Hope this helps

PS: of course, the non-homework way to do this would be to use os.walk:

answer = []
def findAll(fname, dirpath):
    dirpath, dirnames, filenames = os.walk(dirpath)
    for filename in filenames:
        if filename == fname:
            answer.append(os.path.join(dirpath, filename))
    for dirname in dirnames:
        findAll(fname, os.path.join(dirpath, dirname))
# now, answer contains all the required filepaths

EDIT: OP asked for a version that doesn't use global variables:

def findAll(fname, root, answer=None):
    if answer == None:
        answer = []
     for entry inos.listdir(root):
         ifos.path.isdir(os.path.join(root, entry)):
             answer += findAll(fname, os.path.join(root, entry))
         else:
             if entry == fname:
                 answer.append(os.path.join(root, entry))
     return answer

Solution 2:

you need to extend your list with your recursive call

list.extend(findAll(fname,n))

also you can check if something is a directory with os.path.isdir(n)

but I think you have more problems than that with your script

afaik listdir just returns names , not the path of the directory ....

so you will need to call findAll(fname,os.path.join(path,n))

Solution 3:

Not related to the question per se but I believe that os.walk would help you out:

allFiles = []
forroot, dirs, files in os.walk(basedir):
    [allFiles.append(file) forfilein files]

Check out help(os.walk), it comes with a great example on how to use this function.

Solution 4:

try/except is used incorrectly in your code. except clause is executed only if there is an error. Also you don't use the returned value from findAll(). You could skip creating a list inside the function and just yield found items lazily instead:

import os

deffindAll(filename, rootdir): 
    for item in os.listdir(rootdir):
        path = os.path.join(rootdir, item)
        ifnot os.path.isdir(path):
            if item == filename: # don't select dirsyield path
        else: # path is a dirtry:
                for found_path in findAll(filename, path):
                    yield found_path
            except EnvironmentError:
                pass# ignore errorsprint(list(findAll('python', '/usr')))

Output

['/usr/bin/python']

if it is not homework you could use os.walk() to find the files:

import os

def find_all(filename, rootdir):
    for dirpath, dirs, files inos.walk(rootdir):
        for file in files:
            if file == filename:
                yieldos.path.join(dirpath, file)


print(list(find_all('python', '/usr')))

Output

['/usr/bin/python']

It is the same output as expected.

Solution 5:

If you're on a Unix based system you could use find with the subprocess module .. I would reckon this would be the fastest way to retrieve all paths matching a filename. You can then do a split() on the output to make it a list:

>>>import subprocess>>>lst = subprocess.check_output('find . -name "*rst"', shell=True)>>>print lst
    ./SphinxWorkspace/doc/chapter1.rst
    ./SphinxWorkspace/doc/index.rst
    ./SphinxWorkspace/doc/tables.rst

You can always split the command and avoid the shell=True

Checkout: http://docs.python.org/2/library/subprocess.html#using-the-subprocess-module .. Hope this helps!

Post a Comment for "Add An Item Into A List Recursively"