1

I have a horizontally and vertically scrollable table. I get the data for the header and first column from the web service(json). I want to sort the data in ascending order and remove duplicate data from both header and the first column. For removing duplicate values I used the following code:

-(void) requestFinished: (ASIHTTPRequest *) request
{
    NSString *theJSON = [request responseString];

    SBJsonParser *parser = [[SBJsonParser alloc] init];

    NSMutableArray *jsonDictionary = [parser objectWithString:theJSON error:nil];

    headData = [[NSMutableArray alloc] init];
    NSMutableArray *head = [[NSMutableArray alloc] init];

    leftTableData = [[NSMutableArray alloc] init];
    NSMutableArray *left = [[NSMutableArray alloc] init];

    rightTableData = [[NSMutableArray alloc]init];

    for (NSMutableArray *dictionary in jsonDictionary)
    {
        Model *model = [[Model alloc]init];

        model.cid = [[dictionary valueForKey:@"cid"]intValue];
        model.iid = [[dictionary valueForKey:@"iid"]intValue];
        model.yr = [[dictionary valueForKey:@"yr"]intValue];
        model.val = [dictionary valueForKey:@"val"];

        [mainTableData addObject:model];

        [head addObject:[NSString stringWithFormat:@"%ld", model.yr]];
        [left addObject:[NSString stringWithFormat:@"%ld", model.iid]];
    }
    NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:head];
    headData = [[orderedSet array] mutableCopy];

//    NSSet *set = [NSSet setWithArray:left];
//    NSArray *array2 = [set allObjects];
//    NSLog(@"%@", array2);

    NSOrderedSet *orderedSet1 = [NSOrderedSet orderedSetWithArray:left];
    NSMutableArray *arrLeft = [[orderedSet1 array] mutableCopy];

    //remove duplicate enteries from header array
    [leftTableData addObject:arrLeft];


    NSMutableArray *right = [[NSMutableArray alloc]init];
    for (int i = 0; i < arrLeft.count; i++)
    {
        NSMutableArray *array = [[NSMutableArray alloc] init];
        for (int j = 0; j < headData.count; j++)
        {
            /* NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.iid == %ld", [[arrLeft objectAtIndex:i] intValue]];
             NSArray *filteredArray = [mainTableData filteredArrayUsingPredicate:predicate];*/
            NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF.iid == %ld AND SELF.yr == %ld", [[arrLeft objectAtIndex:i] intValue], [[headData objectAtIndex:j] intValue]];
            NSArray *filteredArray = [mainTableData filteredArrayUsingPredicate:predicate];

            if([filteredArray count]>0)
            {
                Model *model = [filteredArray objectAtIndex:0];
                [array addObject:model.val];
            }
        }
        [right addObject:array];
    }
    [rightTableData addObject:right];
}

How will I sort the arrays in ascending order?

Please help.

11
  • may this link will help you. [link]stackoverflow.com/questions/1025674/… Commented Apr 13, 2015 at 5:33
  • I have already removed duplicate values. I want to set the data in ascending order. Commented Apr 13, 2015 at 5:48
  • kindly followed this link. stackoverflow.com/questions/15540829/… Commented Apr 13, 2015 at 6:07
  • For all of the answers you have said that you are getting the error about iid. This is your problem. This is not something wrong with the answers, this is something wrong with your code, your model. All of these answers work. You have given very little information about your data so it's not possible to see why this is happening. Can you include your model code and the sorting code that is showing his error. Commented Apr 13, 2015 at 6:20
  • Also, you don't need to be using SBJSONParser. Just use NSJSONSerialization. Commented Apr 13, 2015 at 6:33

4 Answers 4

1

OK, so you have a model object that looks something like this...

@interface Model: NSObject

@property NSNumber *idNumber;
@property NSNumber *year;
@property NSString *value;

@end

Note, I am intentionally using NSNumber and not NSInteger for reasons that will become clear.

At the moment you are trying to do a lot all in one place. Don't do this.

Create a new object to store this data. You can then add methods to get the data you need. Seeing as you are displaying in a table view sectioned by year and then each section ordered by idNumber then I'd do something like this...

@interface ObjectStore: NSObject

- (void)addModelObject:(Model *)model;

// standard table information
- (NSInteger)numberOfYears;
- (NSInteger)numberOfIdsForSection:(NSinteger)section;

// convenience methods
- (NSNumber *)yearForSection:(NSInteger)section;
- (NSNumber *)idNumberForSection:(NSInteger)section row:(NSInteger)row;
- (NSArray *)modelsForSection:(NSInteger)section row:(NSInteger)row;

// now you need a way to add objects
- (void)addModelObject:(Model *)model;

@end

Now to implement it.

We are going to store everything in one dictionary. The keys will be years and the objects will be dictionaries. In these dictionaries the keys will be idNumbers and the objects will be arrays. These array will hold the models.

So like this...

{
    2010 : {
        1 : [a, b, c],
        3 : [c, d, e]
    },
    2013 : {
        1 : [g, h, u],
        2 : [e, j, s]
    }
}

We'll do this with all the convenience methods also.

@interface ObjectStore: NSObject

@property NSMutableDictionary *objectDictionary;

@end

@implementation ObjectStore

 + (instancetype)init
{
    self = [super init];

    if (self) {
        self.objectDictionary = [NSMutableDictionary dictionary];
    }

    return self;
}

 + (NSInteger)numberOfYears
{
    return self.objectDictionary.count;
}

 + (NSInteger)numberOfIdsForSection:(NSinteger)section
{
    // we need to get the year for this section in order of the years.
    // lets create a method to do that for us.
    NSNumber *year = [self yearForSection:section];

    NSDictionary *idsForYear = self.objectDictionary[year];

    return idsForYear.count;
}

- (NSNumber *)yearForSection:(NSInteger)section
{
    // get all the years and sort them in order
    NSArray *years = [[self.obejctDictionary allKeys] sortedArrayUsingSelector:@selector(compare:)];

    // return the correct year
    return years[section];
}

- (NSNumber *)idNumberForSection:(NSInteger)section row:(NSInteger)row
{
    // same as the year function but for id
    NSNumber *year = [self yearForSection:section];

    NSArray *idNumbers = [[self.objectDictionary allKeys]sortedArrayUsingSelector:@selector(compare:)];

    return idNumbers[row];
}

- (NSArray *)modelsForSection:(NSInteger)section row:(NSInteger)row
{
    NSNumber *year = [self yearForSection:section];
    NSNumber *idNumber = [self idForSection:section row:row];

    return self.objectDictionary[year][idNumber];
}

// now we need a way to add objects that will put them into the correct place.

- (void)addModelObject:(Model *)model
{
    NSNumber *modelYear = model.year;
    NSNumber *modelId = model.idNumber;

    // get the correct storage location out of the object dictionary
    NSMutableDictionary *idDictionary = [self.objectDictionary[modelYear] mutableCopy];

    // there is a better way to do this but can't think atm
    if (!idDictionary) {
        idDictionary = [NSMutableDictionary dictionary];
    }

    NSMutableArray *modelArray = [idDictionary[modelId] mutableCopy];

    if (!modelArray) {
        modelArray = [NSMutableArray array];
    }

    // insert the model in the correct place.
    [modelArray addObject:model];
    idDictionary[modelId] = modelArray;
    self.objectDictionary[modelYear] = idDictionary;
}

@end

With all this set up you can now replace your complex function with this...

-(void) requestFinished: (ASIHTTPRequest *) request
{
    NSString *theJSON = [request responseString];
    SBJsonParser *parser = [[SBJsonParser alloc] init];
    NSDictionary *jsonDictionary = [parser objectWithString:theJSON error:nil];

    for (NSDictionary *dictionary in jsonDictionary)
    {
        Model *model = [[Model alloc]init];

        model.cid = [dictionary valueForKey:@"cid"];
        model.idNumber = [dictionary valueForKey:@"iid"];
        model.year = [dictionary valueForKey:@"yr"];
        model.val = [dictionary valueForKey:@"val"];

        [self.objectStore addModelObject:model];
    }
}

To get the models out for a particular row then just use...

[self.objectStore modelsForSection:indexPath.section row:indexPath.row];

To get the number of sections in the tableview delegate method...

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return [self.objectStore numberOfYears];
}

No messing around with the model in the view controller.

Welcome to the MVC pattern.

There's a crap ton of code here but by placing all the code here you can remove all the complex code from your VC.

Sign up to request clarification or add additional context in comments.

Comments

0

NSSet keeps only non-duplicate objects within themselves so to keep only unique objects in array you can use NSSet as -

Suppose you have array with duplicate objects

NSArray *arrayA = @[@"a", @"b", @"a", @"c", @"a"];
NSLog(@"arrayA is: %@", arrayA);

//create a set with the objects from above array as
//the set will not contain the duplicate objects from above array
NSSet *set = [NSSet setWithArray: arrayA];

// create another array from the objects of the set
NSArray *arrayB = [set allObjects];
NSLog(@"arrayB is: %@", set);

The output from the above looks like:

arrayA is: (
    a,
    b,
    a,
    c,
    a
)
arrayB is: {(
    b,
    c,
    a
)}

and to sort a mutable array in ascending order you can use NSSortDescriptor and sortUsingDescriptors:sortDescriptors. Also you need to provide the key on the basis of which array will be sorted.

NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"key" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
[array sortUsingDescriptors:sortDescriptors];
[sortDescriptor release];

5 Comments

I tried it. I gives error Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x7f8dad8a03d0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key iid.'
can you provide the error message, also have you specified the key in sortDEscriptor?
I have defined model as interface Model : NSObject property (assign, nonatomic) NSInteger cid; property (assign, nonatomic) NSInteger iid; property (assign, nonatomic) NSInteger yr; property (strong, nonatomic) NSString *val;
I have to sort iid and yr
NSSortDescriptor *iidDescriptor = [[NSSortDescriptor alloc] initWithKey:@"iid" ascending:YES]; NSSortDescriptor *yrDescriptor = [[NSSortDescriptor alloc] initWithKey:@"yr" ascending:YES]; NSArray *sortDescriptors = @[iidDescriptor, yrDescriptor]; NSArray *sortedArray = [array sortedArrayUsingDescriptors:sortDescriptors];
0

Here you will get what you want.

//sort description will used to sort array.
NSSortDescriptor *descriptor=[[NSSortDescriptor alloc] initWithKey:@"iid" ascending:YES];
NSArray *descriptors=[NSArray arrayWithObject: descriptor];
NSArray *reverseOrder=[arrLeft sortedArrayUsingDescriptors:descriptors];

reverseOrder is your desire output.

there is another way you can sort objects that followed model.

NSArray *someArray = /* however you get an array */    
NSArray *sortedArray = [someArray sortedArrayUsingComparator:^(id obj1, id obj2) {
 NSNumber *rank1 = [obj1 valueForKeyPath:@"iid"];
NSNumber *rank2 = [obj2 valueForKeyPath:@"iid"];
return (NSComparisonResult)[rank1 compare:rank2];
}];

here sortedArray is our output.

you can replace same things for yr key as well.

3 Comments

Getting error this class is not key value coding-compliant for the key iid.'
@Itaws, are you getting compiler error or crash ? actually this code is working over here so i think there is some minor changes left at your side. can you please give me your arrLeft ?
may be your error due to following reason.stackoverflow.com/questions/3088059/…
0

This is what I did to sort the header data in ascending order and to remove duplicates from both header and leftmost column. Hope this will help others

NSOrderedSet *orderedSet3 = [NSOrderedSet orderedSetWithArray:head3];
headData3 = [[orderedSet3 array] mutableCopy];
[headData3 sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2)
{
    return [str1 compare:str2 options:(NSNumericSearch)];
}];

NSOrderedSet *orderedSet4 = [NSOrderedSet orderedSetWithArray:left3];
NSMutableArray *arrLeft3 = [[orderedSet4 array] mutableCopy];

[leftTableData3 addObject:arrLeft3];

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.