Question

I have a NSArray which looks like this:

@[@"file1", @"directory/testfile", @"directory/otherdir/testfile", @"otherdir/", @"otherdir/otherfile"]

And I'm trying to convert it to a NSDictionary which looks like this:

 @{
  @"directory/":@{
    @"otherdir/":@{
      @"testfile":[..some array with data..]}
    },
    @"testfile":[..some array with data..]
  },
  @"otherdir/":@{
    @"otherfile":[..some array with data..]
  },
  @"file1":[..some array with data..]
}

Basically, a NSDictionary which looks like a file tree. Thanks in advance!

EDIT: The actual array I have is this:

(
    "blog/",
    "blog/code.css",
    "blog/style.css",
    "etc/",
    "etc/awsservices.png",
    "etc/speeds.png",
    "etc/test/",
    "etc/test/other/",
    "etc/test/other/speeds.png",
    "site/",
    "site/dino.png",
    "site/error.css",
    "site/main.css",
    "site/signet.min.js"
)

And the code I wrote for this:

-(NSDictionary*)buildDictionaryWithContentsOfPath:(NSMutableArray*)files {
    NSString *subDir;
    NSMutableDictionary *returnable = [[NSMutableDictionary alloc] initWithDictionary:@{}];
    BOOL directory;

    NSLog(@"%@", files);

    for (S3ObjectSummary *objectSummary in files) {

        if ([[objectSummary key] hasSuffix:@"/"]) {

            if (subDir && [[objectSummary key] hasPrefix:subDir]) {
                NSLog(@"prefixed %@", [objectSummary key]);
                NSMutableDictionary *treeDict = [[NSMutableDictionary alloc] initWithDictionary:@{}];

                [returnable[subDir] setObject:treeDict forKey:[objectSummary key]];

            } else {
                subDir = [objectSummary key];
                NSLog(@"dir %@", [objectSummary key]);
                NSMutableDictionary *treeDict = [[NSMutableDictionary alloc] initWithDictionary:@{}];
                [returnable setObject:treeDict forKey:[objectSummary key]];
            }
            directory = true;

        } else {
            S3GetObjectMetadataRequest *getMetadataRequest = [[S3GetObjectMetadataRequest alloc] initWithKey:[objectSummary key] withBucket:self.bucket.name];
            S3GetObjectMetadataResponse *getMetadataResponse = [self.client getObjectMetadata:getMetadataRequest];

            if (![[objectSummary key] hasPrefix:subDir]) {
                NSLog(@"file %@",[objectSummary key]);
                [returnable setObject:@{@"filename":[objectSummary key], @"directory":@(directory), @"created_at":getMetadataResponse.lastModified} forKey:[objectSummary key]];
            } else {
                for (NSString __strong *pathComp in [[objectSummary key] pathComponents]) {
                    pathComp  = [NSString stringWithFormat:@"%@/", pathComp];
                    NSLog(@"path component %@", pathComp);
                    if (![[objectSummary key] hasSuffix:@"/"]) {
                        if (returnable[pathComp]) {
                            NSLog(@"has comp %@", pathComp);
                            [returnable[pathComp] setObject:@{@"filename":[objectSummary key], @"directory":@(directory), @"created_at":getMetadataResponse.lastModified} forKey:[objectSummary key]];
                        }
                    }

                }

            }
            directory = false;
        }



        //[self.fileTree addObject:@{@"filename":[objectSummary key], @"directory":@(directory), @"created_at":getMetadataResponse.lastModified}];

    }
    return returnable;

}

And the dictionary it returns:

{
    "blog/" =     {
        "blog/code.css" =         {
            "created_at" = "2013-12-07 12:13:37 +0000";
            directory = 0;
            filename = "blog/code.css";
        };
        "blog/style.css" =         {
            "created_at" = "2013-12-07 12:13:36 +0000";
            directory = 0;
            filename = "blog/style.css";
        };
    };
    "etc/" =     {
        "etc/awsservices.png" =         {
            "created_at" = "2013-12-07 12:26:37 +0000";
            directory = 0;
            filename = "etc/awsservices.png";
        };
        "etc/speeds.png" =         {
            "created_at" = "2013-12-07 13:29:27 +0000";
            directory = 0;
            filename = "etc/speeds.png";
        };
        // PROBLEM HERE
        "etc/test/" =         {
        };
        "etc/test/other/" =         {
        };
        "etc/test/other/speeds.png" =         {
            "created_at" = "2013-12-07 17:29:21 +0000";
            directory = 0;
            filename = "etc/test/other/speeds.png";
        };
        // PROBLEM HERE
    };
    "site/" =     {
        "site/dino.png" =         {
            "created_at" = "2013-12-07 12:13:59 +0000";
            directory = 0;
            filename = "pmerino/dino.png";
        };
        "site/error.css" =         {
            "created_at" = "2013-12-07 12:13:59 +0000";
            directory = 0;
            filename = "pmerino/error.css";
        };
        "site/main.css" =         {
            "created_at" = "2013-12-07 12:13:59 +0000";
            directory = 0;
            filename = "pmerino/main.css";
        };
        "site/signet.min.js" =         {
            "created_at" = "2013-12-07 12:13:59 +0000";
            directory = 0;
            filename = "pmerino/signet.min.js";
        };
    };
}

As you can see, this part:

"etc/test/" =         {
};
"etc/test/other/" =         {
};
"etc/test/other/speeds.png" =         {
    "created_at" = "2013-12-07 17:29:21 +0000";
    directory = 0;
    filename = "etc/test/other/speeds.png";
};

Should look like this:

"etc/" =         {
  "test/" =         {
    "other/" = {
      "speeds.png" =         {
          "created_at" = "2013-12-07 17:29:21 +0000";
          directory = 0;
          filename = "etc/test/other/speeds.png";
      };
    };
  };
};
Was it helpful?

Solution

If I understand your problem correctly, this method should be helpful:

// Add the path to the tree. Returns the "node" for this path.
-(NSMutableDictionary *)addFile:(NSString *)path toTree:(NSMutableDictionary *)tree
{
    NSMutableDictionary *node = tree;

    // Split path into components:
    NSArray *components = [path componentsSeparatedByString:@"/"];

    // Create all intermediate dictionaries:
    for (NSUInteger i = 0; i < [components count] - 1; i++) {
        NSString *key = [components[i] stringByAppendingString:@"/"];
        if (node[key] == nil) {
            node[key] = [NSMutableDictionary dictionary];
        }
        node = node[key];
    }

    // Process last component, which is the file name,
    // or "" in the case of a dictionary:
    NSString *name = [components lastObject];
    if ([name length] > 0) {
        node[name] = [NSMutableDictionary dictionary];
        node = node[name];
    }
    return node;
}

If you use it like this:

NSArray *files = ...; // Your array of files
NSMutableDictionary *tree = [NSMutableDictionary dictionary];
for (NSString *path in files) {
    NSMutableDictionary *node = [self addFile:path toTree:tree];
    BOOL isDir = [path hasSuffix:@"/"];
    if (!isDir) {
        node[@"filename"] = path;
    }
}

the resulting dictionary is

{
    "blog/" =     {
        "code.css" =         {
            filename = "blog/code.css";
        };
        "style.css" =         {
            filename = "blog/style.css";
        };
    };
    "etc/" =     {
        "awsservices.png" =         {
            filename = "etc/awsservices.png";
        };
        "speeds.png" =         {
            filename = "etc/speeds.png";
        };
        "test/" =         {
            "other/" =             {
                "speeds.png" =                 {
                    filename = "etc/test/other/speeds.png";
                };
            };
        };
    };
    "site/" =     {
        "dino.png" =         {
            filename = "site/dino.png";
        };
        "error.css" =         {
            filename = "site/error.css";
        };
        "main.css" =         {
            filename = "site/main.css";
        };
        "signet.min.js" =         {
            filename = "site/signet.min.js";
        };
    };
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top