- iOS:根据JSON创建一个树

时间:2015-01-28 09:54:14

标签: ios objective-c json algorithm tree

最近几天,我遇到了一个我无法解决的问题。 实际上,我在JSON中有一些数据。我解析了这个JSON,一切正常。

以下是此JSON的结构:

{
    "obs" : [
    {
        "CategoryId": 1,
        "Title": "Category 1",
        "Description": "Description 1",
        "ParentCategoryId": null
    },
    {
        "CategoryId": 2,
        "Title": "Category 2",
        "Description": "Description 2",
        "ParentCategoryId": null
    },
    {
        "CategoryId": 3,
        "Title": "Category 3",
        "Description": null,
        "ParentCategoryId": null
    },
    {
        "CategoryId": 4,
        "Title": "Category 1.1",
        "Description": "Description 1.1",
        "ParentCategoryId": 1
    },
    {
        "CategoryId": 5,
        "Title": "Category 1.2",
        "Description": "Description 1.2",
        "ParentCategoryId": 1
    },
    {
        "CategoryId": 6,
        "Title": "Category 1.1.1",
        "Description": null,
        "ParentCategoryId": 4
    },
    {
        "CategoryId": 7,
        "Title": "Category 1.1.2",
        "Description": null,
        "ParentCategoryId": 4
    },
    {
        "CategoryId": 8,
        "Title": "Category 1.1.1.1",
        "Description": null,
        "ParentCategoryId": 6
    },
    {
        "CategoryId": 9,
        "Title": "Category 1.3",
        "Description": "Category 1.3",
        "ParentCategoryId": 1
    }

    ]
}

我对这些对象的模型(.h)我正在使用librairie JSONModel:

@class CategoryModel;

@protocol CategoryModel @end

@interface CategoriesModel : JSONModel

@property (nonatomic, strong) NSArray<CategoryModel> * obs;

@end

@interface CategoryModel : JSONModel

@property (nonatomic, strong) NSNumber * CategoryId;
@property (nonatomic, strong) NSString * Title;
@property (nonatomic, strong) NSString<Optional> * Description;
@property (nonatomic, strong) NSNumber<Optional> * ParentCategoryId;

@end

然后,在视图控制器中,在获取JSON的数据并解析它之后,我想制作一个NSDictionary,NSArray或类似树的东西,例如在UITableView中显示这些类别。

我的问题是:我找不到解决方案来“排序”这些数据,并用这个做一棵树。

这是我现在的方法:

- (void)parseJSON
{
    NSError * error;
    NSString *filePath = [[NSBundle mainBundle] pathForResource:@"list" ofType:@"json"];
    NSString *jsonString = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:&error];

    self.myJSON = [[CategoriesModel alloc] initWithString:jsonString error:&error];

    for(CategoryModel * obs in self.myJSON.obs)
    {
        if(obs.ParentCategoryId)
        {
            CategoryModel * parent = [self searchParentObjectForChild:obs];
            NSLog(@"Parent of %@(ID:%ld) : %@(ID:%ld)", obs.Title, [obs.CategoryId integerValue], parent.Title, [parent.CategoryId integerValue]);
        }
        else
        {
            NSLog(@"%@(ID: %@) doesn't have a parent",obs.Title, obs.CategoryId);
        }
    }
}

- (CategoryModel *)searchParentObjectForChild:(CategoryModel *)child
{
    for (CategoryModel * obs in self.myJSON.obs)
    {
        if(obs.CategoryId == child.ParentCategoryId)
        {
            return obs;
        }
    }
    return nil;
}

注意:如果可能,请不要更改JSON的结构。

如果有人知道如何实现这一点,请告诉我。 欢迎任何建议! 谢谢。

1 个答案:

答案 0 :(得分:1)

我假设你有一个这个类的数组,并希望从中构建一个新数组:)

@interface CategoryModel

@property (nonatomic, strong) NSNumber * CategoryId;
@property (nonatomic, strong) NSString * Title;
@property (nonatomic, strong) NSString * Description;
@property (nonatomic, strong) NSNumber * ParentCategoryId;

@end

首先,让我们为每个类别添加另一个属性,当您在app逻辑中使用树时,这将使您的生活更轻松。

@property (nonatomic, strong) NSMutableArray* subCategories;

现在你可能想写这样的东西(请注意,对于大量的类别可能需要很长时间,所以我更喜欢你找到一个已知的算法来构建你的树(可能是AVL树或其他东西))但是对于数百个类别来说,一切都会好起来的。

- (void)findCategoryChildren:(CategoryModel*)category fromArray:(NSMutableArray*)originalCopy currentIndex:(int*)i {
        for (int j = 0; j < originalCopy.count; j++) {
            CategoryModel* childCategory = originalCopy[j];
            if ([childCategory.ParentCategoryId intValue] == [category.CategoryId intValue]) {
                if (category.subCategories == nil) {
                    category.subCategories = [[NSMutableArray alloc] init];
                }
                [category.subCategories addObject:childCategory];
                [originalCopy removeObjectAtIndex:j];
                j--;
                i--;

                // Now find the childs of this child category
                [self findCategoryChildren:childCategory fromArray:originalCopy currentIndex:i];
            }
        }
    }

    - (NSArray*)sort:(NSArray*)original {
        // This is the final array (the tree)
        NSMutableArray* result = [[NSMutableArray alloc] init];

        // This is a copy of the input to minimize the time of the latter iterations
        NSMutableArray* originalCopy = [[NSMutableArray alloc] initWithArray:original];
        for (int i = 0; i < originalCopy.count; i++) {
            CategoryModel* category = originalCopy[i];
            // This is a root category
            if (category.ParentCategoryId == nil) {
                [result addObject:category];
                [originalCopy removeObjectAtIndex:i];
                i--;

                // Now try to find its children
                [self findCategoryChildren:category fromArray:originalCopy currentIndex:&i];
            }
        }

        return result;
    }