emotality
emotality

Reputation: 13025

See if NSDictionary key is in another NSArray

Database (
    {
        to = (NSString *)
        from = (NSString *)
        subject = (NSString *)
        uid = int
        body = (NSString *)
    }, { ...
)

Downloaded (
    {
        to = (NSString *)
        from = (NSString *)
        subject = (NSString *)
        uid = int
        body = (null)
    }, { ...
)

I immediately pull and load an NSArray of about 200 NSDictionay objects from my Database into my UITableView, then I download an NSArray of the same structured NSDictionary but without a body.

Q: How do I go through all 200 Downloaded NSDictionary to see if it isn't already in my Database NSArray by matching the key: "uid"?

Upvotes: 0

Views: 98

Answers (3)

Eike
Eike

Reputation: 638

Beware of nested loops :) If you use Arturo's example (which works!) and download 1000 messages, you will have a potential of O(n*m) = 1000*200 = 200.000 "calculation steps"

Larme's attempt is pretty elegant (I like predicates!) but it's hard to predict the time it will use for execution, because it's all encapsulated within NSPredicate.

So another attempt, based on Larme's example data, would be to use a dictionary with the uid as the key for fast lookup.

    NSMutableDictionary *databaseLookupDictionary = [[NSMutableDictionary alloc]init];
    databaseLookupDictionary[@(0)] = @{@"to":@"0",@"from":@"0",@"uid":@(0), @"body":@"0"};
    databaseLookupDictionary[@(1)] = @{@"to":@"1",@"from":@"1",@"uid":@(1), @"body":@"0"};
    databaseLookupDictionary[@(2)] = @{@"to":@"2",@"from":@"2",@"uid":@(2), @"body":@"0"};
    databaseLookupDictionary[@(3)] = @{@"to":@"3",@"from":@"3",@"uid":@(3), @"body":@"0"};


    /* your download code */

    // example data 
    NSMutableArray *downloadedData = [[NSMutableArray alloc]init];
    [downloadedData addObject: @{@"to":@"0",@"from":@"0",@"uid":@(3)}];
    [downloadedData addObject: @{@"to":@"0",@"from":@"0",@"uid":@(4)}];

    for(NSDictionary *downloadDataDict in downloadedData)
    {
        // will be executed for message #4
        if(![databaseLookupDictionary.allKeys containsObject:downloadDataDict[@"uid"]])
        {
            NSLog(@"Unknown message data found: %@", downloadDataDict);
        }
    }

This runs in linear time (O(n)*O(1)) so you should be fine with the performance. But keep in mind: if your message database count grows, you should think about searching directly in CoreData.

Upvotes: 0

Larme
Larme

Reputation: 26036

This should do the trick:

NSArray *arrayOfNew = [arrayDownload filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT (uid IN %@)", [arrayDataBase valueForKey:@"uid"]];

Tested with this sample data, if someone want to test it:

NSDictionary *dictionary0 = @{@"to":@"0",@"from":@"0",@"uid":@(0), @"body":@"0"};
NSDictionary *dictionary1 = @{@"to":@"1",@"from":@"1",@"uid":@(1), @"body":@"0"};
NSDictionary *dictionary2 = @{@"to":@"2",@"from":@"2",@"uid":@(2), @"body":@"0"};
NSDictionary *dictionary3 = @{@"to":@"3",@"from":@"3",@"uid":@(3), @"body":@"0"};

NSDictionary *dictionary4 = @{@"to":@"4",@"from":@"4",@"uid":@(2)};
NSDictionary *dictionary5 = @{@"to":@"5",@"from":@"5",@"uid":@(5)};

NSArray *arrayDataBase = @[dictionary0, dictionary1, dictionary2, dictionary3];
NSArray *arrayDownload = @[dictionary4, dictionary5];

//So the dictionary4 shouldn't be kept, and dictionary5 should be kept.
NSArray *arrayNew = [arrayDownload filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"NOT (uid IN %@)", [arrayDataBase valueForKey:@"uid"]]];
NSLog(@"arrayNew: %@", arrayNew);

Output:

arrayNew: (
        {
        from = 5;
        to = 5;
        uid = 5;
    }

Upvotes: 3

Arturo Marzo
Arturo Marzo

Reputation: 41

With this code you can iterate in two arrays called "Downloaded" and "Database" and check if their uid match. I'm not sure if you're looking for a more elegant solution.

for (NSDictionary *dictDownloaded in Downloaded) {
    for (NSDictionary *dictDatabase in Database) {
        if ([dictDownloaded objectForKey:@"uid"] == [dictDatabase objectForKey:@"uid"]) {
            NSLog(@"Object with uid: %d is in database", [[dictDownloaded objectForKey:@"uid"] intValue]);
        }
    }
}

Upvotes: 1

Related Questions