Malcolm
Malcolm

Reputation: 1807

Good lambda expression or better way to reduce for each loop

I want to get sub folders of a root folder. And i am able to get it through the below code. But has a issue when the sub folder has a sub folder in it and i over come it writing a second for each loop. But what if the second sub folder has a sub folder under it. So there will be an infinte for each loop, so i have to overcome it. Any help is worthfull.Thanks in advance.

foreach (Folder.Folder folder in FolderService.Instance.GetSubFolders(userContext, folderID))
            {
                folderById.Add(folder.FolderID, folder);
                foreach (Folder.Folder sfolder in FolderService.Instance.GetSubFolders(userContext, folder.FolderID))
                {
                    folderById.Add(sfolder.FolderID, sfolder);
                }
            }

Upvotes: 4

Views: 1459

Answers (5)

Malcolm
Malcolm

Reputation: 1807

I got it done . Here's the code.

 private List<Folder.Folder> GetAllF(AbstractUserContext userContext, string folderID)
    {
        List<Folder.Folder> listFold = new List<Folder.Folder>();
        foreach (Folder.Folder folder in FolderService.Instance.GetSubFolders(userContext, folderID))
        {
            listFold.Add(folder);
            listFold.AddRange(GetAllF(userContext,folder.FolderID));
        }
        return listFold;
    }

Upvotes: 0

Antony Koch
Antony Koch

Reputation: 2053

Is there a good reason for the dictionary to not be at field level rather than passing it through the recursive call?

Dictionary<string, int> folderById = new Dictionary<string,int>();
public void Start()
{
    // code for initial context + folder id
    RecurseFolders(userContext, folderId);
}

public void RecurseFolders(string userContext, int folderId)
{
    foreach (Folder.Folder folder in FolderService.Instance.GetSubFolders(userContext, folderID)) {
        folderById.Add(folder.FolderID, folder);
        RecurseFolders(userContext, folder.folderId);
    }
}

Upvotes: 1

Tomas Petricek
Tomas Petricek

Reputation: 243061

Here is an example how to write recursive traversal using recursive lambda expression and using SelectMany method from LINQ:

Func<string, IEnumerable<string>> folders = null;
folders = s =>
  Directory.GetDirectories(s).SelectMany(dir =>
    Enumerable.Concat(new[] { dir }, folders(dir)));

foreach (var d in folders("C:\\Tomas\\Writing\\Academic"))
  Console.WriteLine(d);

The first line declares the lambda expression in advance, because we use it later inside its definition. This is not a problem, because it will be used after it has been initialized, but the C# compiler requires that we declare it earlier.

The body of the lambda expression calls SelectMany, which calls the given lambda expression for each element of the input sequence and concatenates all returned sequences - our lambda returns the current directory dir and then all recursively calculated subdirectories of dir.

This is probably not particularly efficient, but it definitely shows how you can use lambda functions to write short code (it could be optimized however, F# libraries do that, because this is more common pattern in F#).

Just for comparison, the same thing in F# looks like this:

let folders s = seq {
  for dir in Directory.GetDirectories(s) 
    yield dir
    yield! folders dir }

The code uses sequence expressions which are like C# iterators. yield corresponds to yield return and yield! yields all elements of a sequence (it is like iterating over it using foreach and yielding individual elements using yield return, but more efficient).

Upvotes: 0

AxelEckenberger
AxelEckenberger

Reputation: 16926

Here are two additional samles using labdas. The first uses a function declared locally to recurse over the items (DirectoryInfos in this case) and the second uses an instance method.

class Program
{
    static void Main(string[] args) {
        string path = @"d:\temp";

        Func<DirectoryInfo, IEnumerable<DirectoryInfo>> func = null;
        func = (folder) => {
            return new[] { folder }.Concat(folder.GetDirectories().SelectMany(x => func(x)));
        };

        IEnumerable<DirectoryInfo> dirs = (new DirectoryInfo(path)).GetDirectories().SelectMany(x => func(x));

        IEnumerable<DirectoryInfo> dirs2 = GetSubDirs(new DirectoryInfo(path));
    }

    public static IEnumerable<DirectoryInfo> GetSubDirs(DirectoryInfo dir) {
        yield return dir;
        foreach (var subDir in GetSubDirs(dir)) yield return subDir;
    }

    // method 2 even shorter
    public static IEnumerable<Directory> GetSubDirs2(DirectoryInfo dir) {
        return new[] { dir }.Concat(dir.GetDirectories().SelectMany(x => GetSubDirs2(x)));
    }
}

Upvotes: 0

Anton Gogolev
Anton Gogolev

Reputation: 115769

Perfect place for recursion:

... TraverseFolder(rootFolderID, userContext)
{
    var folderById = new ...;
    TraverseFolder(folderById, rootFolderID, userContext);

    return folderById;
}

void TraverseFolder(folderById, folderID, userContext)
{
    var folders = FolderService.Instance.GetSubFolders(userContext, folderID);
    foreach(var folder in folders)
    {
        folderById.Add(folder.FolderID, folder);
        TraverseFolder(folder.FolderID);
    }
}

Theoretically, you can have recursive lambdas, but they are waay too complicated.

Upvotes: 10

Related Questions