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;
}
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
}
- (void)buttonSave:(UIButton *)bttnSave
{
UILabel *lbl = (UILabel *)[self.view viewWithTag:kTagLblText];
[dicStore setValue:lbl.textColor forKey:#"Text Color"];
// fltValue is float type
[dicStore setObject:fltValue forKey:#"font"];
[dicStore setValue:strtextView forKey:#"Text Style"];
[arrStoreDic addObject:dicStore];
}
If We can store this then any one can help me please do
Simply:
dicStore[#"font"] = #(fltValue);
However it's troubling that dicStore is an instance variable that you want to store into an array, which leads me to believe you will end up with an array of the same dictionary, containing the same values.
Instead create a new dictionary each time and store it into the array (unless, of course, other code needs to see this dictionary). The current implementation is very brittle.
NSDictionary *dic = [NSDictionary dictionaryWithObjectsAndKeys:
[NSArray arrayWithObjects:[NSNumber numberWithFloat:0.5], [NSNumber numberWithFloat:0.7], [NSNumber numberWithFloat:0.2], nil],
nil];
The above code is used to add float values in Dictionary
NSMutableDictionary, NSarray, NSSet and other collection classes accept only objects, and a float variable is a primitive. You have to create a NSNumber object from your float :
NSNumber * floatObject =[NSNumber numberWithFloat:fltValue]
[dicStore setObject:floatObject forKey:#"font"];
Using literals, your code can be simplified to :
-(void)buttonSave:(UIButton *)bttnSave
{
UILabel *lbl = (UILabel *)[self.view viewWithTag:kTagLblText];
dicStore[#"Text Color"] = lbl.textColor;
dicStore[#"font"] = #(fltValue);
dicStore[#"Text Style"] = strtextView;
[arrStoreDic addObject:dicStore];
}
To get back the float value, it's pretty simple :
NSNumber * floatNumber = dicStore[#"font"];
float floatValue = floatNumber.floatValue;
NSDictionary *dict = #{#"floatProperty":[NSNumber numberWithFloat:floatValue]};
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 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.
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]};
}