将JSON解析为树结构

时间:2014-05-14 02:15:05

标签: ios objective-c json uitableview

我正在开发一个需要tableView分类杂货商品列表的项目。每个类别都可以具有 n 深度。来自API的JSON响应如下所示。

"items":[
{
  "id":"5366f8d3e4b0e44dc2d4a6fb",
  "name":"String Cheese"
  "description":"Sargento String Cheese",
  "categorization":[
    [
      "Dairy",
      "Cheese"
    ]
  ]
},
{
  "id":"5366f8d3e4b0e44dc2d1a6fb",
  "name":"Budlight 6-pk"
  "description":"Budlight 12-pk",
  "categorization":[
    [
      "Beverages",
      "Alcohol",
      "Beer"
    ]
  ]
}
]

现在我从项目词典创建Item对象并将它们存储在如下所示的可变数组中。

NSArray *itemsArray = [response objectForKey:items];

NSMutableArray *itemsMutableArray = [[NSMutableArray alloc] init];
for(NSDictionary *itemDict in itemsArray){
    Item *itemObj = [[Item alloc] initWithDictionary:itemDict]
    [itemsMutableArray addObject:itemObj];
}

我想遍历itemsMutableArray并创建一个树数据结构,其中包含从根到每个项的路径。然后,我希望能够在每个级别的类别中将树用作tableViews的数据源。

这是我的Item类标题的样子。

@interface Item : NSObject

@property (nonatomic, strong) NSString *id;
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *description;
@property (nonatomic, strong) NSArray  *categorization;

@end

......和实施

#import "Item.h"

@implementation Item

- (id)initWithDictionary:(NSDictionary *)objDictionary{
    if (self = [super init]) {
        self.id = [objDictionary valueForKey:@"id"];
        self.name = [objDictionary valueForKey:@"name"];
        self.description = [objDictionary valueForKey:@"description"];
        self.categorization = [objDictionary valueForKey:@"categorization"];
    }
    return self;
}

@end

我对树数据结构和递归不是很熟悉。我非常感谢有关如何处理此问题的任何帮助。谢谢!

2 个答案:

答案 0 :(得分:0)

如果需要简单的节点树数据结构。这样怎么样? 希望这一点帮助。

标题

@interface ItemCategory : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic) ItemCategory *parent;
@property (nonatomic, strong) NSMutableArray *children;

-(id)initWithName:(NSString *)n parent:(ItemCategory *)p;
@end

@interface CategoryTree : NSObject

@property (nonatomic, strong) ItemCategory *root;

-(ItemCategory *)_getChildCategory:(ItemCategory *)category name:(NSString *)name;
-(ItemCategory *)_addChildCategory:(ItemCategory *)category name:(NSString *)name;
-(void)_dumpCategory:(ItemCategory *)category depth:(int)depth;

-(void)dump;
-(ItemCategory *)getCategory:(NSArray *)arr;
-(void)addCategory:(NSArray *)arr;

@end

来源

@implementation CategoryTree
@synthesize root;

-(id)init {
    if (self = [super init]) {
        root = [[ItemCategory alloc] initWithName:@"root" parent:nil];
    }
    return self;
}

-(ItemCategory *)_getChildCategory:(ItemCategory *)category name:(NSString *)name {
    for (ItemCategory *child in category.children)
        if ([child.name isEqualToString:name])
            return child;

    return nil;
}

-(ItemCategory *)_addChildCategory:(ItemCategory *)category name:(NSString *)name {
    ItemCategory *child = [self _getChildCategory:category name:name];
    if (child)
        return child;
    child = [[ItemCategory alloc] initWithName:name parent:category];
    [category.children addObject:child];

    return child;
}

-(void)_dumpCategory:(ItemCategory *)category depth:(int)depth{
    NSString *parentStr = @"";
    ItemCategory *parent = category.parent;
    while (parent) {
        parentStr = [NSString stringWithFormat:@"%@%@%@", parent.name, parentStr.length > 0 ? @">" : @"", parentStr];
        parent = parent.parent;
    }
    NSLog(@"%@%@%@", parentStr, parentStr.length > 0 ? @">" : @"", category.name);

    for (ItemCategory *child in category.children) {

        [self _dumpCategory:child depth:depth + 1];
    }
}

-(void)dump {
    [self _dumpCategory:root depth:0];
}

-(ItemCategory *)getCategory:(NSArray *)arr {
    ItemCategory *category = root;
    for (NSString *categoryName in arr) {
        category = [self _getChildCategory:category name:categoryName];
        if (!category)
            return nil;
    }
    return category;
}

-(void)addCategory:(NSArray *)arr {
    if ([self getCategory:arr])
        return;

    ItemCategory *category = root;
    for (NSString *categoryName in arr) {
        ItemCategory *childCategory = [self _getChildCategory:category name:categoryName];
        if (!childCategory) {
            childCategory = [self _addChildCategory:category name:categoryName];
        }
        category = childCategory;
    }
}
@end

用法

CategoryTree *tree = [[CategoryTree alloc] init];
[tree addCategory:@[@"Dairy", @"Cheese"]];
[tree addCategory:@[@"Dairy", @"Milk"]];
[tree addCategory:@[@"Beverages", @"Alcohol", @"Beer"]];
[tree addCategory:@[@"Beverages", @"Alcohol", @"Wine"]];
[tree addCategory:@[@"Beverages", @"Non-Alcohol", @"Cola"]];
[tree dump];

结果

root
root>Dairy
root>Dairy>Cheese
root>Dairy>Milk
root>Beverages
root>Beverages>Alcohol
root>Beverages>Alcohol>Beer
root>Beverages>Alcohol>Wine
root>Beverages>Non-Alcohol
root>Beverages>Non-Alcohol>Cola

答案 1 :(得分:0)

我找到了实现你需要的方法。我不知道它是如何优化的,因为我没有收到多少物品。实施如下。

您需要先在Item.h @property (nonatomic, strong) NSMutableDictionary *catTree;

中添加此词典

接下来这样做以获取树

[itemsMutableArray enumerateObjectsUsingBlock:^(Item *itm, NSUInteger i,BOOL *stop){
        itm.catTree = [NSMutableDictionary dictionary];
        NSString *dairy = @"",*beverage = @"";
        for (NSArray *catArray in itm.categorization) {
            /*
                Everything below is written assuming the format of the JSON will be "as-is"
             */

            if ([catArray containsObject:@"Dairy"]) {
                //Take everything except Dairy
                NSArray *stripedArray = [catArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != \"Dairy\""]];
                int i = 0;
                //Loop through the array to get any sub categories.
                while (i < stripedArray.count) {
                    dairy = [dairy stringByAppendingString:[NSString stringWithFormat:(i == stripedArray.count-1)?@"%@ ":@"%@->",stripedArray[i]]]; //Space at the end to account for similar entry in the same category for e.g two dairy products.
                    i++;
                }
            } else  if ([catArray containsObject:@"Beverages"]) {
                NSArray *stripedArray = [catArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != \"Beverages\""]];
                int i = 0;
                while (i < stripedArray.count) {
                    beverage = [beverage stringByAppendingString:[NSString stringWithFormat:(i == stripedArray.count-1)?@"%@ ":@"%@->",stripedArray[i]]];
                    i++;
                }
            }
        }


        //Set the category tree for every item using a dictionary
        [itm.catTree setValue:dairy forKey:@"Dairy"];
        [itm.catTree setValue:beverage forKey:@"Beverage"];

        NSLog(@"%@",itm.catTree);
    }];

上面的代码为你的json提供了以下输出

{
    Beverage = "";
    Dairy = "Cheese ";
}
{
    Beverage = "Alcohol->Beer ";
    Dairy = "";
}

适用于多种饮料

{
   Beverage = "Alcohol->Beer Alcohol->Wine->Red Soda->Coke ";
   Dairy = "";
}

希望这有帮助。