I need to create a dictionary with for a search, based on IDs, but if no ID gets selected, 0 has to be stored.
Now I can obviously do it like this:
NSNumber* cityID;
NSNumber* zoneID; //These two do get value, just showing for their class
NSDictionary *cityDictionary = #{#"CityID": [NSNumber numberWithInt:(int)cityId], #"CityZoneID": [NSNumber numberWithInt:(int)zoneId]};
I feel it's really messy like that. It gets cast to int, then turned back to NSNumber...
Try this
// May be syntax change but you need to initialise with zero first
NSNumber* cityID = [NSNumber numberWithInt:0];
NSNumber* zoneID = [NSNumber numberWithInt:0]; //Init with Zero then you can added value for this if no value default will be 0
NSDictionary *cityDictionary = #{#"CityID": [NSNumber numberWithInt:(int)cityId], #"CityZoneID": [NSNumber numberWithInt:(int)zoneId]};
This may help
What about
NSDictionary *cityDictionary = #{
#"CityID" : (cityID == nil ? #0 : cityID),
#"CityZoneID" : (zoneID == nil ? #0 : zoneID)
};
NSNumber* cityID;
NSNumber* zoneID;
if((cityID == nil)||(zoneID == nil))
{
NSDictionary *cityDictionary = #{#"CityID": [NSNumber numberWithInt:0], #"CityZoneID": [NSNumber numberWithInt:0]};
}
Related
I' want to filter NSARRAY based on an object named id, I've specific set of Ids that I want to filter and want to be first in NSARRAY.
I stored the following Ids as NSNUMEBR
NSNumber *A = [NSNumber numberWithInt:1122];
NSNumber *B = [NSNumber numberWithInt:1345];
NSNumber *C = [NSNumber numberWithInt:1667];
NSNumber *D = [NSNumber numberWithInt:1223];
NSNumber *E = [NSNumber numberWithInt:1213];
NSNumber *F = [NSNumber numberWithInt:1123];
NSNumber *G = [NSNumber numberWithInt:1555];
NSNumber *H = [NSNumber numberWithInt:1666];
NSNumber *I = [NSNumber numberWithInt:1567];
These are the set of ids that I want to filter and want to be first in my NSARRAY (Can be NSMutableArray for operation)
EDIT 1:
the NSARRAY is basically getting the id object as
Ids = [dict valueForKey:#"id"];
That selective ids are stored in NSNUMBER A to I
It is unclear what you are asking, as indicated by the down votes and comments. But let's see if we can help. I think the following pseudo-code algorithm is what you are asking for:
MutableArray frontItems, rearItems;
for every item in sourceArray
if item["id"] is in the collection of specific IDs
then add item to end of frontItems
else add item to end of rearItems
add rearItems to end of frontItems to give result
Write that in Objective-C and I think you have what you want.
HTH
//Creat array have all item : A->I
NSNumber *A = [NSNumber numberWithInt:1122];
NSNumber *B = [NSNumber numberWithInt:1345];
NSNumber *C = [NSNumber numberWithInt:1667];
NSNumber *D = [NSNumber numberWithInt:1223];
NSNumber *E = [NSNumber numberWithInt:1213];
NSNumber *F = [NSNumber numberWithInt:1123];
NSNumber *G = [NSNumber numberWithInt:1555];
NSNumber *H = [NSNumber numberWithInt:1666];
NSNumber *I = [NSNumber numberWithInt:1567];
NSMutableArray *arr = [[NSMutableArray alloc] initWithObjects:A,B,C,...,I, nil];
for (NSNumber *idx in arr) {
// To do
}
I have a NSDictionary with NSString as keys and NSNumber as values such as the following
NSDictionary *dictionary = #{#"Apple" : [NSNumber numberWithInt: 6],
#"Banana" : [NSNumber numberWithInt: 1],
#"Peach" : [NSNumber numberWithInt: 14],
#"Lychee" : [NSNumber numberWithInt: 1]};
Here, I would like to find the lowest key and value, which in this example would be tie between Lychee : 1 and Banana: 1. Ordinarlly for a smaller dictionary, I would just sort through all the values as suggested by this answer and retrieve the first (or the tied) object in the array based on the ranking. However, I was wondering if there is a way to do it if the NSDictionary is very large, where I could just pluck the lowest key-value pairs?
Thanks!
As #Tommy said, there's no option other than to do a linear search. Sorting the dictionary will impose a function of O(n log(n)), while a linear search is obviously O(n). You'd need to use the following:
NSDictionary *dictionary = #{#"Apple" : [NSNumber numberWithInt: 6],
#"Banana" : [NSNumber numberWithInt: 1],
#"Peach" : [NSNumber numberWithInt: 14],
#"Lychee" : [NSNumber numberWithInt: 1]};
NSString *lowestKey = nil;
int lowestValue = 0;
for (NSString *key in dictionary)
{
int value = [dictionary[key] intValue];
if (!lowestKey || value < lowestValue)
{
lowestKey = key;
lowestValue = value;
}
}
NSLog(#"Lowest: %#: %d", lowestKey, lowestValue);
This code has several advantages: enumerateKeysAndObjectsUsingBlock: doesn't need to lookup any keys but accesses the keys and values directly from the dictionary's data structures, avoiding expensive lookups. Using an NSNumber compare operation makes the code work for large integers, fractional numbers and NSDecimalNumber.
__block NSString* lowestKey = nil;
__block NSNumber* lowestNumber = nil;
[dictionary enumerateKeysAndObjectsUsingBlock:^(id key, NSNumber* obj, BOOL *stop) {
if ([lowestNumber == nil || [obj compare:lowestNumber] == NSOrderedAscending)
{
lowestKey = key;
lowestNumber = obj;
}
}];
If there's no structure in place to avoid a linear search then you'll have to do a linear search.
E.g.
NSNumber *minValue = [[dictionary allValues] valueForKeyPath:#"#min.self"];
NSString *aLowestKey = [dictionary allKeysForObject:minValue][0];
That'll actually likely be two such searches; it'd be faster manually to iterate the keys and latch on the least key. But it'd be more and slightly more opaque code so pick based on where this code falls on the speed versus maintainability requirement curve.
(typed on an iPhone from a cafe; please forgive slight errors)
I am trying to optimize function which returns NSMutableDictionary like this :
-(NSMutableDictionary *)getValuses{
NSNumber *n1 = [NSNumber numberWithInt:-1];
NSNumber *n2 = [NSNumber numberWithInt:-1];
NSNumber *n3 = [NSNumber numberWithInt:-1];
NSNumber *n4 = [NSNumber numberWithInt:-1];
NSNumber *n5 = [NSNumber numberWithInt:-1];
if (self.k1)
n1 = self.k1;
if (self.k2)
n2 = self.k2;
if (self.k3)
n3 = self.k3;
if (self.k4)
n4 = self.k4;
if (self.k5)
n5 = self.k5;
NSMutableDictionary * dictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:n1,[NSNumber numberWithInt:2],n2,[NSNumber numberWithInt:3],n3,[NSNumber numberWithInt:4],n4,[NSNumber numberWithInt:5],n5,[NSNumber numberWithInt:6], nil];
return dictionary;
}
I run this function in loop more than 1 000 000 times, so any optimisation is good. It works but I want it to work significantly faster.
do you really need dictionnary with -1 values ?
you can avoid all the "if/then" stuff (I heard it can be quite slow for a cpu) if you just do
NSMutableDictionary * dictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:k1,[NSNumber numberWithInt:2],k2,[NSNumber numberWithInt:3],k3,[NSNumber numberWithInt:4],k4,[NSNumber numberWithInt:5],k5,[NSNumber numberWithInt:6], nil];
// then you can do things like this
id obj = [dictionary objectForKey:#2];
if (obj)
NSLog(#"dict with good values");
else
NSLog(#"old dict with -1");
-(NSMutableDictionary *)getValuses{
NSNumber *n1 = [NSNumber numberWithInt:-1];
NSMutableDictionary * dictionary = [[NSMutableDictionary alloc]initWithObjectsAndKeys:(self.k1)? self.k1:n1,[NSNumber numberWithInt:2],(self.k2)? self.k2:n1,[NSNumber numberWithInt:3],(self.k3)? self.k3:n1,[NSNumber numberWithInt:4],(self.k4)? self.k4:n1,[NSNumber numberWithInt:5],(self.k5)? self.k5:n1,[NSNumber numberWithInt:6], nil];
return dictionary;
}
try the above code....
You can try something like this (not tested):
-(NSMutableDictionary *)getValuses {
NSNumber *n = [NSNumber numberWithInt:-1];
NSMutableDictionary * dictionary =
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
self.k1 ? self.k1 : n,[NSNumber numberWithInt:2],
self.k2 ? self.k2 : n,[NSNumber numberWithInt:3]...
return dictionary;
}
You can reduce the number of NSNumber objects created, and you can use the new literal syntax to at least make the code shorter & easier to read. You can also halve the number of property accesses. Whether any of this will have a big impact on performance you'll have to find out.
-(NSMutableDictionary *)getValuses
{
NSNumber *n = #(-1);
return #{ #2: (self.k1 ?: n), #3: (self.k2 ?: n), #4: (self.k3 ?: n),
#5: (self.k4 ?: n), #6: (self.k5 ?: n)
};
}
(The expression a ?: b is shorthand for a ? a : b but a will only be evaluated once, hence the halving of the number of property accesses.)
Try this! dispatch_appy method is for create loops and execute the code inside in concurrent queues. This is a better way of executing big loops.
dispatch_apply blocks - Apple Documentation
I didn't compile it but it should work. Hope it help to give you a clue. Good luck!
-(NSMutableDictionary *)getValuses{
//add the values here
NSMutableArray *array = [#[self.k1,self.k2,self.k3,self.k4,self.k5]mutableCopy];
NSMutableDictionary * dictionary = [#{}mutableCopy];
//this kind of block is better for big loops...
size_t count = array.count;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_apply(count, queue, ^(size_t i) {
id value = [array objectAtIndex:i];
[dictionary setObject:value?value:(#-1) forKey:#(i)];
});
return dictionary;
}
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
I'm trying to iterate over an NSMutableDictionary and I cannot seem to get what I want. I have a dictionary mapping strings to colors like so...
squareColors = [NSMutableDictionary dictionaryWithObjects: [NSMutableArray arrayWithObjects:
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:0],
nil]
forKeys: [NSMutableArray arrayWithObjects:
#"yellow",
#"blue",
#"green",
#"purple",
#"orange",
nil]];
Over time the value of each entry will increase. Every once in a while I want to look into the dictionary and select the color with the highest count. How might I do that? Here's what I'm trying, but I'm unfamiliar with blocks.
__block int mostSquares = 0;
__block NSString* color = #"";
/* Look through the dictionary to find the color with the most number of squares */
[squareColors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
NSLog(#"%# => %#", key, obj);
NSInteger count = [key integerValue];
if (count > mostSquares)
{
color = key;
mostSquares = count;
}
}];
You have a very simple bug in your code. This line:
NSInteger count = [key integerValue];
should be:
NSInteger count = [obj integerValue];
'key' is the color name, obj is the number. As you have it, count gets set to 0 for each iteration because calling integerValue on a non-numeric string gives you 0.
Simple solution using your example:
NSMutableArray *arrayNumbers = [NSMutableArray arrayWithObjects:
[NSNumber numberWithInt:0],
[NSNumber numberWithInt:1],
[NSNumber numberWithInt:2],
[NSNumber numberWithInt:6],
[NSNumber numberWithInt:4],
nil];
NSMutableArray *arrayColours = [NSMutableArray arrayWithObjects:
#"yellow",
#"blue",
#"green",
#"purple",
#"orange",
nil];
NSMutableDictionary *squareColors = [NSMutableDictionary dictionaryWithObjects:arrayNumbers
forKeys:arrayColours];
NSUInteger indexOfArray = [arrayNumbers indexOfObject:[arrayNumbers valueForKeyPath:#"#max.intValue"]];
NSLog (#"Colour with largest value is %#", [arrayColours objectAtIndex:indexOfArray]);
Can you store your Keys into an array and iterate using that array? That would probably be the most efficient solution, since you'll need to know every key anyway.