See if NSDictionary key is in another NSArray - ios

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"?

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;
}

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]);
}
}
}

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.

Related

How to print the contents of NSSet?

I query and get a NSSet which contains customer address from web. Since I'm new to objective c development I don't know how to get country,zip code etc from that set.So I followed Objective-C How to print NSSet on one line (no trailing comma / space) but my output is in the form of object "0x7f99997b7a50". How can I print all the strings in the set? Thanks in advance.
I tried like this
NSArray *ar = [customer.addresses allObjects];
for (int i = 0; i<ar.count; i++)
{
NSLog(#"arr %#",ar[i]);
}
But the output is arr:
<BUYAddress: 0x7fd451f6e050>
If you have a custom object, you may need to override description
Without overriding:
-(void) testCustomObjects
{
CustomObject *co1 = [[CustomObject alloc] init];
co1.name = #"James Webster";
co1.jobTitle = #"Code Monkey";
CustomObject *co2 = [[CustomObject alloc] init];
co2.name = #"Holly T Canine";
co2.jobTitle = #"Pet Dog";
NSSet *set = [NSSet setWithObjects:co1, co2, nil];
NSLog(#"%#", [set allObjects]);
}
produces:
2016-12-02 11:45:55.342 Playground[95359:4188387] (
"<CustomObject: 0x600000037a20>",
"<CustomObject: 0x60000003ae20>"
)
However, if I override the description method in my CustomObject class:
-(NSString*) description
{
return [NSString stringWithFormat:#"%# (%#)", self.name, self.jobTitle];
}
I get the following:
(
"Holly T Canine (Pet Dog)",
"James Webster (Code Monkey)"
)
If for whatever reason, you can't add a description method, you'd just have to access the relevant parts of the object; something like the following:
NSArray *ar = [customer.addresses allObjects];
for (int i = 0; i<ar.count; i++)
{
NSLog(#"arr %# (%#)",ar[i].name, ar[i].address);
}
I've had a little look at the library you're using. Try the following:
for (BUYAddress *address in customer.addresses)
{
NSLog(#"Address: %#, %#, %#", address.address1, address.address2, address.city);
}
Consider NSSet below,
NSSet *theNSSet = [NSSet setWithObjects:#"Chennai",#"Mumbai",#"Delhi", nil];
Convert it into NSArray using
NSArray *array = [theNSSet allObjects]; // theNSSet is replaced with your NSSet id
Then print it like
NSLog(#"%#",array);
Output im getting
(
Chennai,
Delhi,
Mumbai
)
In your case:
- (NSMutableSet *)addressesSet {
[self willAccessValueForKey:#"addresses"];
NSMutableSet *result = (NSMutableSet *)[self mutableSetValueForKey:#"addresses"];
[self didAccessValueForKey:#"addresses"];
NSLog(#"%#",[result allObjects]); // printing the nsset
return result;
}

How to get JSON data parse from Arrays of dictionary iOS

list = ({
clouds = 24;
speed = "4.31";
temp = {
day = "283.84";
eve = "283.84";
night = "283.84";
};
}),
Please can anyone tell me what am I doing wrong - I want to display list-->temp-->day value in table first I am trying to get data in an array which is terminating.
Here is my code am I doing any wrong
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:dataBuffer options:-1 error:nil];
NSLog(#"%#",json);
NSMutableDictionary * list = [json objectForKey:#"list"];
NSMutableArray *arrays = [[NSMutableArray alloc]initWithCapacity:0];
for (NSDictionary *lists in [list allValues]) {
[arrays addObject:[list valueForKey:#"temp"]];
}
If you want to access day then use below line,
NSString *day = [json valueForKeyPath:#"list.temp.day"];
Your list is an array, so if you want to do your things without changing much, you can replace:
NSMutableDictionary * list = [json objectForKey:#"list"];
With:
NSMutableDictionary * list = [[json objectForKey:#"list"] objectAtIndex:0];

how to group array of nsdictionary according to the value inside the element

I have array of dictionary that needs to be grouped according to PO which is part of the element and also get the total of quantityOrdered according to the same PO.
The PO is dynamic it means it can be any value that needs to be filtered and compute the quantityOrderd accordingly.
Please help.
{
PO = PO2;
QuantityReceived = 1;
},
{
PO = PO1;
QuantityReceived = 3;
},
{
PO = PO1;
QuantityReceived = 3;
},
{
PO = PO3;
QuantityReceived = 2;
},
{
PO = PO2;
QuantityReceived = 2;
},
{
PO = PO3;
QuantityReceived = 4;
},
{
PO = PO1;
QuantityReceived = 1;
},
Apology for the confusion or incomplete question but i need to create a new array of dictionary with similar like this :
{
PO = PO1;
TotalQuanityReceived=7;
LineItems=3;
},
{
PO = PO2;
TotalQuanityReceived=3;
LineItems=2;
},
{
PO = PO3;
TotalQuanityReceived=6;
LineItems=2;
},
i updated my example and make it easy to read.
- (NSArray *)whatever:(NSArray *)dictionaries
{
NSMutableArray *results = [[NSMutableArray alloc] init];
NSMutableDictionary *resultsByPO = [[NSMutableDictionary alloc] init];
for (NSDictionary *dictionary in dictionaries) {
id po = [dictionary objectForKey:#"PO"];
NSMutableDictionary *result = [resultsByPO objectForKey:po];
if (result == nil) {
result = [[NSMutableDictionary alloc] init];
[resultsByPO setObject:result forKey:po];
[results addObject:result];
[result setObject:po forKey:#"PO"];
}
double total = [[result objectForKey:#"TotalQuantityReceived"] doubleValue];
total += [[dictionary objectForKey:#"QuantityOrdered"] doubleValue];
int count = 1 + [[result objectForKey:#"Count"] intValue];
[result setObject:#(total) forKey:#"TotalQuantityReceived"];
[result setObject:#(count) forKey:#"Count"];
}
return results;
}
More pain will come with PO values not conforming to NSCopying.
You can do it the clever way with KVC or the stupid easy way. Let's do it the stupid easy way!
Make an empty NSMutableDictionary. Let's call it dict.
Cycle through your array of dictionaries. For each dictionary:
Fetch its PO. Call that value thisPO.
Fetch dict[thisPO]. Was it nil?
a. Yes. Okay, so this particular PO has not yet been encountered. Set dict[thisPO] to this dictionary's quantity received (as an NSNumber).
b. No. Turn that value into an integer, add this dictionary's quantity received, and set the total back into dict[thisPO] (as an NSNumber).
Done! The result is not quite what you asked for; the result looks like this:
{
PO1 = 100;
PO2 = 120;
...
}
But now, you see, the work of totalling is done and it is easy to transform that into an array of dictionaries if that is what you want.
Not 100% sure if this is what you are saying or not, but to sort an array of dictionaries based on one of the elements it would look something like this.
NSDictionary *d1 = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithDouble:100],#"PO",
[NSNumber numberWithDouble:0], #"Category",
nil];
NSDictionary *d2 = [[NSDictionary alloc] initWithObjectsAndKeys:
[NSNumber numberWithDouble:50],#"PO",
[NSNumber numberWithDouble:90], #"Category",
nil];
NSArray *unsorted = #[d1, d2];
NSArray *sortedArray;
sortedArray = [unsorted sortedArrayUsingComparator:^NSComparisonResult(id a, id b) {
NSDictionary *first = (NSDictionary*)a;
NSDictionary *second = (NSDictionary*)b;
NSNumber *firstPO = [first objectForKey:#"PO"];
NSNumber *secondPO = [second objectForKey:#"PO"];
return [firstPO compare:secondPO];
}];
NSLog(#"unsorted = %#", unsorted);
NSLog(#"sorted = %#", sortedArray);
I wasn't really sure what PO was, so I just used an NSNumber as an example. Look at this page for an overview of how you would compare a customer object. http://nshipster.com/nssortdescriptor/.
Then you can loop through the array, now in the correct order and build your next NSDictionary.

Get a value from nsdictionary

I want to give a key value from my NSDictionary and get the value associated to it.
I have this:
NSArray *plistContent = [NSArray arrayWithContentsOfURL:file];
NSLog(#"array::%#", plistContent);
dict = [plistContent objectAtIndex:indexPath.row];
cell.textLabel.text = [dict objectForKey:#"code"];
with plistContent :
(
{
code = world;
key = hello;
},
{
code = 456;
key = 123;
},
{
code = 1;
key = yes;
}
)
So how do I get "hello" by giving the dictionary "world"?
If I understand your question correctly, you want to locate the dictionary where "code" = "world" in order to get the value for "key".
If you want to keep the data structure as it is, then you will have to perform a sequential search, and one way to do that is simply:
NSString *keyValue = nil;
NSString *searchCode = #"world";
for (NSDictionary *dict in plistContents) {
if ([[dict objectForKey:#"code"] isEqualToString:searchCode]) {
keyValue = [dict objectForKey:#"key"]); // found it!
break;
}
}
However if you do alot of this searching then you are better off re-organizing the data structure so that it's a dictionary of dictionaries, keyed on the "code" value, converting it like this:
NSMutableDictionary *dictOfDicts = [[NSMutableDictionary alloc] init];
for (NSDictionary *dict in plistContents) {
[dictOfDicts setObject:dict
forKey:[dict objectForKey:#"code"]];
}
(note that code will break if one of the dictionaries doesn't contain the "code" entry).
And then look-up is as simple as:
NSDictionary *dict = [dictOfDicts objectForKey:#"world"]);
This will be "dead quick".
- (NSString*) findValueByCode:(NSString*) code inArray:(NSArray*) arr
{
for(NSDictonary* dict in arr)
{
if([[dict valueForKey:#"code"] isEqualToString:code])
{
return [dict valueForKey:#"key"]
}
}
return nil;
}

Using NSPredicate to filter an object and a key(that needs to be split)

I have the following dictionary set up(Object, Key)
0, "10;0.75,0.75"
1, "0;2.25,2.25"
3, "1;3.5,2.0"
4, "1;4.5,3.0"
5, "2;6.0,5,0"
What I want to filter will be based on the object AND the key. The object is a NSNumber. The key is a string but i really don't want the entire string. I want to split the string separated by the semicolon and take the first index of the split which would yield the strings 10,0,1,1 or 2 depending on which object I was looking for.
As a specific example:
Are there any keys that are equal to #"1" with an object that is greater than 3.
In this case i should expect back YES since object 4 has a key that is equal to #"1", after i do the split.
I guess I was looking for a clever way to define a NSPredicate to do the split on the key separated by the semicolon and then filter(compare, etc) based on that. Let me know if you have any questions or need additional info.
A very naive implementation that I could think of
- (BOOL)hasKey:(NSString *)key withValueGreaterThan:(id)object{
NSDictionary *dictionary = #{#"10;0.75,0.75": #0,
#"0;2.25,2.25" : #1,
#"1;3.5,2.0" : #3,
#"1;4.5,3.0" : #4,
#"2;6.0,5,0" : #5};
NSPredicate *keyPredicate = [NSPredicate predicateWithFormat:#"SELF BEGINSWITH %#",key];
NSArray *filteredKeys = [[dictionary allKeys]filteredArrayUsingPredicate:keyPredicate];
for (NSString *k in filteredKeys) {
NSNumber *value = dictionary[k];
if (value>object) {
return YES;
}
}
return NO;
}
Use
BOOL hasValue = [self hasKey:#"1;" withValueGreaterThan:#3];
Sample Code:
NSDictionary* dict = #{ #"10;0.75,0.75":#0,
#"0;2.25,2.25":#1,
#"1;3.5,2.0":#3,
#"1;4.5,3.0":#4,
#"2;6.0,5,0":#5};
__block NSString* foundKey = nil;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString* key, NSNumber* obj, BOOL *stop) {
//here goes condition
//get substr
NSArray* arr = [key componentsSeparatedByString:#";"];
int num = [[arr objectAtIndex:0]integerValue];
if ((num == 1)&&([obj integerValue]>3)) {
foundKey = key;
stop = YES;
}
}];
if (foundKey) {
NSLog(#"%#:%#",foundKey,[dict objectForKey:foundKey]);
}
Just use the following method:
-(BOOL)filterFromDictionary:(NSDictionary*)dict keyEqual:(NSString*)key greaterthanObj:(NSString*)obj
{
NSArray *allKeys = [dict allKeys];
for (NSString *eachkey in allKeys) {
NSString *trimmedKey = [self trimKeyuntill:#";" fromString:eachkey];
NSString *trimmedValue = [dict objectForKey:eachkey];
if ([trimmedKey isEqualToString:key] && [trimmedValue intValue] > [obj intValue]) {
return YES;
}
}
return NO;
}
call the above method with your dictionary like:
NSDictionary *dict = [NSDictionary dictionaryWithObjects:[NSArray arrayWithObjects:#"1",#"1",#"3",#"4",#"5", nil] forKeys:[NSArray arrayWithObjects:#"10;0.75,0.75",#"0;2.25,2.25",#"1;3.5,2.0",#"1;4.5,3.0",#"2;6.0,5,0", nil]];
[self filterFromDictionary:dict keyEqual:#"1" greaterthanObj:#"3"]
I assumed all your objects are nsstrings. otherwise change the intValue

Resources