this question is based on performance, i am getting desired results.
i have a array of dictionaries like this:
Printing description of arrAppointmentDictionary:
<__NSArrayM 0x16f962a0>(
{
"component_id" = 159;
total = 1;
},
{
"component_id" = 165;
total = 1;
},
{
"component_id" = 177;
total = 1;
},
{
"component_id" = 191;
total = 1;
},
{
"component_id" = 193;
total = 1;
}
)
i searched in dictionary based on keys like this:
for (int i = 0; i<arrAppointmentDictionary.count; i++)
{
NSMutableDictionary *appointmentDictionary = [arrAppointmentDictionary objectAtIndex:i];
NSArray *keys = [appointmentDictionary allKeys];
for (NSString *key in keys)
{
#autoreleasepool {
NSLog(#"Key is %#", key);
if([[appointmentDictionary objectForKey: key] isEqualToString:[rs stringForColumn:#"id"]])
{
layout.numberOfAppointments = [appointmentDictionary objectForKey: #"total"];
NSLog(#"number of appointments are >>>>>>>>>>>>>>>>> %#", [appointmentDictionary objectForKey: #"total"]);
}
}
}
}
i get the results accurate.
how to increase performance/memory optimisations of this for loop as it is called from another while loop.
thanks & regards.
Here's one way:
NSString *wantedId = [rs stringForColumn:#"id"];
for (NSMutableDictionary *appointmentDictionary in arrAppointmentDictionary) {
if ([appointmentDictionary[#"id"] isEqualToString:wantedId]) {
layout.numberOfAppointments = appointmentDictionary[#"total"];
NSLog(#"number of appointments are >>>>>>>>>>>>>>>>> %#", appointmentDictionary[#"total"]);
break;
}
}
Related
I have an array of dictionaries that I am trying to get the Max score for each player in the array. Each player can have multiple entries I am trying to get an array of dictionaries of each players best score.
NSArray
[0] - NSDictionary
- [0] Score: (double)20.7
- [1] NameID: (int) 1
- [2] Date
[1] - NSDictionary
- [0] Score: (double)25
- [1] NameID: (int) 1
- [2] Date
[2] - NSDictionary
- [0] Score: (double)28
- [1] NameID: (int) 2
- [2] Date
[3] - NSDictionary`
- [0] Score: (double)26
- [1] NameID: (int) 3
- [2] Date
I have tried using NSPredicate predicateWithFormat but I am only able to get back the max for everything in the array not related to the name.
Expected Output:
NSArray
[1] - NSDictionary
- [0] Score: (double)25
- [1] NameID: (int) 1
- [2] Date
[2] - NSDictionary
- [0] Score: (double)28
- [1] NameID: (int) 2
- [2] Date
[3] - NSDictionary`
- [0] Score: (double)26
- [1] NameID: (int) 3
- [2] Date
Thanks for the help.
You can't use an NSPredicate for this, since you want to determine the maximum score for several different players. Under the covers, NSPredicate iterates the array anyway, so using your own loop isn't any less efficient. In the following code I have assumed that the scores and player names are wrapped in NSNumber
-(NSArray *)maxScoresForPlayers:(NSArray *)playerScores {
NSMutableDictionary *maxScores = [NSMutableDictionary new];
for (NSDictionary *player in playerScores) {
NSNumber *playerID = (NSNumber *)player[#"NameID"];
NSDictionary *playerMax = maxScores[playerID];
if (playerMax == nil) {
playerMax = player;
} else {
NSNumber *currentMax = (NSNumber *)[playerMax[#"Score"];
NSNumber *playerScore = (NSNumber *)player[#"Score"];
if ([playerScore doubleValue] > [currentMax doubleValue]) {
playerMax = player;
}
}
maxScores[playerID] = playerMax;
}
return([maxScores allValues];
}
You can do it manually like this:
NSMutableDictionary *maxScoresDict = [NSMutableDictionary dictionary];
for (NSDictionary *score in scoresArray) {
NSNumber *key = score[#"NameID"];
NSNumber *savedMax = maxScoresDict[key][#"Score"];
NSNumber *currentMax = maxScoresDict[key][#"Score"];
if (savedMax == nil || [currentMax doubleValue] > [savedMax doubleValue]) {
maxScoresDict[key] = score;
}
}
NSArray *maxScoresArray = [maxScoresDict allValues];
Try this:
NSArray *objects = #[#{#"Score": #(20.7),
#"NameID": #(1),
#"Date": [NSDate date]},
#{#"Score": #(25),
#"NameID": #(1),
#"Date": [NSDate date]},
#{#"Score": #(28),
#"NameID": #(2),
#"Date": [NSDate date]},
#{#"Score": #(26),
#"NameID": #(3),
#"Date": [NSDate date]}];
NSMutableArray *users = [NSMutableArray array];
for (NSInteger i=0; i<objects.count; i++) {
NSDictionary *dict = objects[i];
NSNumber *nameID = dict[#"NameID"];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"self.NameID==%#", nameID];
NSInteger index = [users indexOfObjectPassingTest:^BOOL(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
BOOL found = [predicate evaluateWithObject:obj];
return found;
}];
if (index != NSNotFound) {
NSNumber *score1 = dict[#"Score"];
NSNumber *score2 = users[index][#"Score"];
if (score1.doubleValue > score2.doubleValue) {
[users replaceObjectAtIndex:index withObject:dict];
}
}
else {
[users addObject:dict];
}
}
NSLog(#"%#", users);
- (NSArray *)getBestScores:(NSArray *)players {
NSMutableDictionary *best = [[NSMutableDictionary alloc] init];
for (NSDictionary *p in players) {
NSDictionary *b = [best valueForKey:[p valueForKey:#"NameID"]];
if (!b || [[p valueForKey:#"Score"] doubleValue] > [[b valueForKey:#"Score"] doubleValue])
[best setValue:p forKey:[p valueForKey:#"NameID"]];
}
return [best allValues];
}
// Get Max Value of integer element from Array of Dictonaries.
// Example Array Starts
<paramArray>(
{
DicID = 1;
Name = "ABC";
ValuetoCalculateMax = 2800;
},
{
DicID = 2;
Name = "DEF";
ValuetoCalculateMax = 2801;
},
{
DicID = 3;
Name = "GHI";
ValuetoCalculateMax = 2805;
}
)
// Example Array Ends
// Implementation
int MaxintegerValue=0;
MaxintegerValue=[self getMaxValueFromArrayofDictonaries:paramArray];
// Implementation Ends
// Function Starts
-(int)getMaxValueFromArrayofDictonaries:(NSArray *)paramArray
{
int MaxValue=0;
NSMutableDictionary *dic=[[NSMutableDictionary alloc]init];
for ( int i=0; i<[paramArray count]; i++ )
{
dic=[paramArray objectAtIndex:i];
if ([[dic valueForKey:#"ValuetoCalculateMax"] intValue] > MaxValue)
{
MaxValue=[[dic valueForKey:#"ValuetoCalculateMax"] intValue];
}
else
{
MaxValue=MaxValue;
}
}
return MaxValue;
}
// Function Ends
What you need to do is find scores for each user, then find the max score out of it.
- (void)findMaxScoreForUser:(int)userId {
NSDictionary *dict0 = [NSDictionary dictionaryWithObjects:#[#27.0,#3] forKeys:#[#"Score",#"UserID"]];
NSDictionary *dict1 = [NSDictionary dictionaryWithObjects:#[#25.0,#2] forKeys:#[#"Score",#"UserID"]];
NSDictionary *dict2 = [NSDictionary dictionaryWithObjects:#[#23.0,#3] forKeys:#[#"Score",#"UserID"]];
NSArray *arr = [NSArray arrayWithObjects:dict0,dict1,dict2, nil];
NSMutableArray *scores = [NSMutableArray array];
for (NSDictionary *dict in arr) {
int userID = [[dict valueForKey:#"UserID"] intValue];
if (userId == userID) {
[scores addObject:[dict valueForKey:#"Score"]];
}
}
int max = [[scores valueForKeyPath:#"#max.intValue"] intValue];
}
In my application you can import data through a tab separated values file. I don't have any challenge until I parse "locations" that have multiple items attached to them. If you scroll to the very bottom of the second method you can see how I create a relationship between items and the locations that contain them inside Core Data. The problem occurs when I parse past column 31 in a location. It doesn't attach those items to the location. So my question is this; is there a limit to columns in the NSArray that is parsed by CHCSVParser? If not, what would cause this limiting to 31 columns?
I've posted the two methods that I encounter the bug with below.
+ (void) importDatabaseTSVURL:(NSURL*)url {
// First check if there is already a database. If so, stop import.
if ([XSELLocation locations].count > 0) return;
if ([XSELItem items].count > 0) return;
if ([XSELVendor vendors].count > 0) return;
NSError *error;
NSArray *array = [NSArray arrayWithContentsOfDelimitedURL:url options:CHCSVParserOptionsSanitizesFields delimiter:'\t' error:&error];
if ([[[array firstObject] firstObject] isEqualToString:#"XSELINVENTORYTSV"]) {
for (NSArray *row in array) {
[XSELSettings parseImportDataRow:row];
}
}
}
+ (void) parseImportDataRow:(NSArray*)array {
// Create logic to seperate data entered next
static NSString *operation = #"none";
if ([array.firstObject isEqualToString:#"ITEMLIST"]) {
operation = #"items";
return;
}
else if ([array.firstObject isEqualToString:#"LOCATIONLIST"]) {
operation = #"locations";
return;
}
else if ([array.firstObject isEqualToString:#"VENDORLIST"]) {
operation = #"vendors";
return;
}
else if ([array.firstObject isEqualToString:#"ENDLIST"]) { // Create database, relate objects, and clean up the data
operation = #"none";
return;
}
// Parse rows to the correct array.
if ([operation isEqualToString:#"vendors"]) {
NSLog(#"adding vendor");
XSELVendor *vendor = [XSELVendor addVendor];
vendor.vendorID = [NSNumber numberWithInteger:[[array objectAtIndex:0] integerValue]];
[XSELSettings nextVendorID];
vendor.name = [array objectAtIndex:1];
vendor.contactID = [array objectAtIndex:2];
}
else if ([operation isEqualToString:#"items"]) {
NSLog(#"adding item");
XSELItem *item = [XSELItem addItem];
item.itemID = [NSNumber numberWithDouble:[[array objectAtIndex:0] integerValue]];
[XSELSettings nextItemID];
item.name = [array objectAtIndex:1];
item.smallPackageName = [array objectAtIndex:2];
item.bigPackageName = [array objectAtIndex:3];
item.smallPerBig = [NSNumber numberWithDouble:[[array objectAtIndex:4] integerValue]];
item.buildTo = [NSNumber numberWithDouble:[[array objectAtIndex:5] integerValue]];
item.price = [NSNumber numberWithDouble:[[array objectAtIndex:6] integerValue]];
// Relate preferred vendor to item
for (XSELVendor *vendor in [XSELVendor vendors]) {
if ([vendor.vendorID.stringValue isEqualToString:[array objectAtIndex:7]]) {
item.preferredVendor = vendor;
break;
}
}
}
else if ([operation isEqualToString:#"locations"]) {
NSLog(#"adding location");
XSELLocation *location = [XSELLocation addLocation:[array objectAtIndex:1]];
location.locationID = [NSNumber numberWithInteger:[[array objectAtIndex:0] integerValue]];
[XSELSettings nextLocationID];
location.position = [NSNumber numberWithInteger:[[array objectAtIndex:2] integerValue]];
// Relate location with items
unsigned long itemsRelatedCount = array.count - 3;
NSLog(#"\n\nitemsRelated: %lu\n\n", itemsRelatedCount);
NSMutableOrderedSet *items = [NSMutableOrderedSet orderedSet];
for (int i = 0; i < itemsRelatedCount; i++) {
NSString *itemID = [array objectAtIndex:i];
for (XSELItem *item in [XSELItem items]) {
if ([item.itemID.stringValue isEqualToString:itemID]) {
[items addObject:item];
break;
}
}
}
location.items = items;
}
}
I am sorting an array.
There are three types of elements in the array.
1. featured
2. organic and
3. claimed.
Among them, I want to sort only organic elements and keep the featured and claimed elements at their own index.
Below is my code in which, I am extracting the claimed and featured indices in a dictionary as key being the index and value is the array element.
//Initialization
NSMutableArray *sortedArray = nil;
NSMutableDictionary *tempFeaturedDictionary = [[NSMutableDictionary alloc]init];
NSMutableDictionary *tempClaimedDictionary = [[NSMutableDictionary alloc]init];
NSMutableArray *tempOrganicArray = [[NSMutableArray alloc]init];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)[array objectAtIndex:i];
if (isFeaturedObj.featured) {
[tempFeaturedDictionary setObject:isFeaturedObj forKey:[#(i)stringValue]];
}else if (isFeaturedObj.claimed)
{
[tempClaimedDictionary setObject:isFeaturedObj forKey:[#(i)stringValue]];
}else
[tempOrganicArray addObject:isFeaturedObj];
}
Again I am adding the claimed and featured back to their original indices after sorting as:
sortedArray = [NSMutableArray arrayWithArray:[tempOrganicArray sortedArrayUsingDescriptors:sortDescriptorsArray]];
for (int i = 0; i<sortedArray.count; i++) {
for (NSString *key in tempFeaturedDictionary) {
if ( [[#(i)stringValue] isEqualToString: key] ) {
[sortedArray insertObject:[tempFeaturedDictionary objectForKey:[#(i)stringValue]] atIndex:i];
}}
for (NSString *key in tempClaimedDictionary) {
if ([[#(i)stringValue]isEqualToString:key ]) {
[sortedArray insertObject:[tempClaimedDictionary objectForKey:[#(i)stringValue]] atIndex:i];
}
}
}
The code works good. Except there is claimed/(and)featured elements at the last index of the 'array'. Because the 'sortedArray' index remains less than the 'array.count' in this scenario.
Thanks in advance.
Update -
I receive response array of type:
[{featured1 featured2}, {organic1, organic2..}, {claimed1}, {featured11, featured12}, {organic11, organic12..}, {claimed2}, ..]
and I am allowed to sort only organic elements within this array. Featured and claimed should not loose their original index position.
I would iterate through the array, extracting the organics to sort. Then sort your organic array. Then iterate through the original array taking either the element from the original array or an element from the sorted organics array as appropriate.
NSMutableArray *organicsArray = [NSMutableArray new];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)array[i];
if ((!isFeaturedObj.featured) && (!isFeaturedObj.claimed)) {
[organicsArray addObject:isFeaturedObj];
}
}
NSMutableArray *sortedOrganicsArray = [[organicsArray sortedArrayUsingDescriptors:sortDescriptorsArray] mutableCopy];
NSMutableArray *outputArray = [NSMutableArray new];
for (int i = 0; i < array.count; i++) {
DRListing *isFeaturedObj = (DRListing*)array[i];
if ((!isFeaturedObj.featured) && (!isFeaturedObj.claimed)) {
[outputArray addObject:sortedOrganicsArray[0]];
[sortedOrganicsArray removeObjectAtIndex:0];
} else {
[outputArray addObject:isFeaturedObject];
}
}
You could possibly make it a little more efficient if you reversed your sort order for the organics array since then you could say
[outputArray addObject:[sortedOrganicsArray lastObject]];
[sortedOrganicsArray removeLastObject];
But if your array isn't particularly large then the performance improvement will probably be negligible.
Maybe this is an alternative:
NSMutableArray *organics = [NSMutableArray new];
NSMutableArray *others = [NSMutableArray new];
for (DRListing *isFeaturedObj in array) {
if (isFeaturedObj.organic) {
[organics addObject:isFeaturedObj];
} else {
[others addObject:isFeaturedObj];
}
}
NSMutableArray *sorted = [NSMutableArray alloc]initWithObjects:organics,others, nil];
You can take the first 2 functions. The others are what I used for testing.
- (DRListing *)getNextObjectFromArray:(NSArray *)array WithStartingIndex:(int)index
{
for (int i=index; i<array.count; i++) {
DRListing *obj = (DRListing*)[array objectAtIndex:i];
if (!obj.featured && !obj.claimed)
{
return obj;
}
}
return nil;
}
- (void)sortArray:(NSMutableArray *)array
{
for (int pass = 0; pass<array.count-1; pass++) {
for (int i=0; i<array.count-1; i++) {
DRListing *obj = [self getNextObjectFromArray:array WithStartingIndex:i];
int foundIndex = (int)[array indexOfObject:obj];
DRListing *obj2 = [self getNextObjectFromArray:array WithStartingIndex:foundIndex+1];
int foundIndex2 = (int)[array indexOfObject:obj2];
if (obj!=nil && obj2 !=nil) {
if (obj.value >= obj2.value) {
[array exchangeObjectAtIndex:foundIndex withObjectAtIndex:foundIndex2];
}
i = foundIndex;
}
}
}
NSLog(#"Sorted Data: %#",array);
}
- (NSMutableArray *)testData
{
NSMutableArray *array = [NSMutableArray new];
for (int i=0; i<20; i++) {
DRListing *obj = [DRListing new];
obj.featured = i*i%2;
obj.claimed = i%2;
obj.value = i*3%10;
[array addObject:obj];
}
NSLog(#"Test Data: %#",array);
return array;
}
#interface DRListing : NSObject
#property (nonatomic) BOOL featured;
#property (nonatomic) BOOL claimed;
#property (nonatomic) int value;
#end
Hi This is what am getting from server
{
1 = {
"display_name" = "One";
id = 1;
};
2 = {
"display_name" = "Two";
id = 2;
};
13 = {
"display_name" = "abc";
id = 13;
};
15 = {
"display_name" = "aaa";
id = 15;
};
4 = {
"display_name" = "ffd";
id = 4;
};
3 = {
"display_name" = "abdfdfc";
id = 3;
};
5 = {
"display_name" = "aasdfsdfa";
id = 5;
};
}
i need to sort this based on "id" this is what am looking as output
Expecting output
{
1 = {
"display_name" = "One";
id = 1;
};
2 = {
"display_name" = "Two";
id = 2;
};
3 = {
"display_name" = "abdfdfc";
id = 3;
};
4 = {
"display_name" = "ffd";
id = 4;
};
5 = {
"display_name" = "aasdfsdfa";
id = 5;
};
13 = {
"display_name" = "abc";
id = 13;
};
15 = {
"display_name" = "aaa";
id = 15;
};
}
This code i have tried and its not working
//vehiclesDictionary real dictionary
NSMutableArray *sortedKeys=[[NSMutableArray alloc]init];
for(NSString *item in [vehiclesDictionary allKeys]){
[sortedKeys addObject:[NSNumber numberWithInt:[item intValue]]];
}
NSArray *sortedKeysArray = [sortedKeys sortedArrayUsingSelector: #selector(compare:)];
NSLog(#"%#",sortedKeysArray);
NSMutableDictionary *sortedValues = [[NSMutableDictionary alloc] init];
for (NSString *key in sortedKeysArray) {
[sortedValues setValue:[vehiclesDictionary valueForKey:[NSString stringWithFormat:#"%#",key]] forKey:key];
}
NSLog(#"%#",sortedValues);
Pls help me
You cannot sort an NSDictionary, it is an unsorted collection type. You will need to store your keys in an array and sort this and use it to access the NSDictionary in order.
Based on your code above, it could be modified as follows, e.g.
NSDictionary *dict = [NSDictionary dictionary];
NSArray *sortedKeys = [[dict allKeys] sortedArrayUsingSelector:#selector(compare:)];
for (NSString *key in sortedKeys) {
NSLog(#"%#", [d objectForKey:key]);
// Do something with the object here
}
Here you can pass around the sortedKeys array with the NSDictionary, and use the sortedKeys array for in-order access to your NSDictionary.
A more concise approach to get the array, but with the same outcome as above, would be using:
NSDictionary -keysSortedByValueUsingComparator as shown here.
As others have mentioned, NSDictionaries cannot be sorted. However, you could do something like this:
-(NSArray *)sortedKeysFromDictionary:(NSDictionary *)dictionary ascending:(BOOL)ascending
{
/* get all keys from dictionary */
NSArray *allKeys = [dictionary allKeys];
NSString *key = #"id"; // using "id" as key here
/* sort keys */
NSSortDescriptor *dateDescriptor = [NSSortDescriptor sortDescriptorWithKey:key ascending:ascending];
return [NSArray arrayWithArray:[allKeys sortedArrayUsingDescriptors:#[dateDescriptor]]];
}
This will take all the keys from your dictionary, sort them in ascending or descending order as you desire and return that as an NSArray. This array can then be used to access the original dictionary. A sample implementation would look something like this:
for (NSString *key in [self sortedKeysFromDictionary:sampleDic ascending:NO])
{
/* get value from current key */
NSDictionary *currentDic = [sampleDic objectForKey:key];
}
I need to show a grouped tableview from the below data. I need to categorise the below array based on "account_type".
For Eg: I need to show Table Section Heading "Savings" and list all savings type accounts, then similarly get Unique account types and gave that as section header and account numbers in table rows. I am able to get section headers using NSSet, but how to get row counts and display it in a UITableView.
<__NSArrayM 0x7f8ef1e8b790>(
{
"account_no" = 123;
"account_type" = Savings;
},
{
"account_no" = 123456;
"account_type" = Savings;
},
{
"account_no" = 00000316;
"account_type" = "DPN STAFF NON EMI";
},
{
"account_no" = 1000000552;
"account_type" = "DPN STAFF EMI LOANS";
})
I need to display the above data in UITableView like
section 0 --- Savings
Row 1 - 123
Row 2 - 123456
section 1 ---> DPN STAFF NON EMI
Row 1 - 00000316
Thanks,
AKC
You can make use of NSDictionary also. The below code worked perfectly.
if([arrySelectedDetails count] >0){
grouped = [[NSMutableDictionary alloc] initWithCapacity:arrySelectedAcctDetails.count];
for (NSDictionary *dict in arrySelectedDetails) {
id key = [dict valueForKey:#"type"];
NSMutableArray *tmp = [grouped objectForKey:key];
if (tmp == nil) {
tmp = [[NSMutableArray alloc] init];
[grouped setObject:tmp forKey:key];
}
[tmp addObject:dict];
}
typeArray= [[NSMutableArray alloc]init];
for(NSDictionary *groupId in arrySelectedDetails){
if(!([typeArray count]>0)){
[typeArray addObject:[groupId valueForKey:#"type"]];
}
else if (![typeArray containsObject:[groupId valueForKey:#"type"]]) {
[typeArray addObject:[groupId valueForKey:#"type"]];
}
}
}
Then for UITableView Delegates:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [typeArray count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [grouped[[typeArray objectAtIndex:section]] count]
}
Try the below code:
NSMutableArray *resultArray = [NSMutableArray new];
NSArray *groups = [arrySelectedAcctDetails valueForKeyPath:#"#distinctUnionOfObjects.account_type"];
NSLog(#"%#", groups);
for (NSString *groupId in groups)
{
NSMutableDictionary *entry = [NSMutableDictionary new];
[entry setObject:groupId forKey:#"account_type"];
NSArray *groupNames = [arrySelectedAcctDetails filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"account_type = %#", groupId]];
for (int i = 0; i < groupNames.count; i++)
{
NSString *name = [[groupNames objectAtIndex:i] objectForKey:#"account_no"];
[entry setObject:name forKey:[NSString stringWithFormat:#"account_no%d", i + 1]];
}
[resultArray addObject:entry];
}
NSLog(#"%#", resultArray);
Output:
{
"account_no1" = 00000316;
"account_type" = "DPN STAFF NON EMI";
},
{
"account_no1" = 123;
"account_no2" = 123456;
"account_type" = Savings;
},