Reputation: 13025
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
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
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
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