I have an app that I need to support till the original developer comes back.
Basically it has a method that groups the data into sections of UITableView.
It all works very nicely and shows the Sections by DogLocation.
This is the code I have :
-(void)loadSortedData:(NSString*)breedToLoad fieldToSort:(NSString*)sortField
{
self.items = [DbUtilities getDogsByBreed:breedToLoad SortField:sortField];
NSMutableDictionary * theDictionary = [NSMutableDictionary dictionary];
for ( Dog * object in self.items )
{
NSMutableArray * theMutableArray = [theDictionary objectForKey:object.DogLocation];
if ( theMutableArray == nil )
{
theMutableArray = [NSMutableArray array];
[theDictionary setObject:theMutableArray forKey:object.DogLocation];
}
[theMutableArray addObject:object];
}
self.sortedMediaItems = [[theDictionary allKeys] sortedArrayUsingSelector:#selector(localizedCaseInsensitiveCompare:)];
/* Save `theDictionary` in an instance variable */
self.theSource = theDictionary;
[self.tableView reloadData];
}
I call this method in my ViewDidLoad by using following syntax:
[self loadSortedData:#"Cattle" fieldToSort:#"DogLocation"];
What I am trying to achieve is to be able to call this method by passing a value in the method e.g so that I can sort it by other fields and not just the DogLocation e.g DogAge,DogPrice .
Could anyone kindly direct me or show me a better way to achieve this instead of writing big if else statement?
Thank you in advance.
You can try using the M13OrderedDictionary, it's based on NSObject not NSDictionary but it does the job required: https://github.com/Marxon13/M13OrderedDictionary
As long as sortField is always a valid property of Dog, you can use Key-Value Coding.
for ( Dog * object in self.items )
{
id key = [object valueForKey:sortField];
NSMutableArray * theMutableArray = [theDictionary objectForKey:key];
if ( theMutableArray == nil )
{
theMutableArray = [NSMutableArray array];
[theDictionary setObject:theMutableArray forKey:key];
}
[theMutableArray addObject:object];
}
Related
I have two arrays of key-value pairs. Both these arrays contain different key-value pairs. I want to find elements in the first array that are not part of the second array based on a particular key.
Example:
1st Array - [{id=1, name="foo"},
{id=2, name="bar"}]
2nd Array - [{id=2, name="abc"},
{id=1, name="xyz"}]
Is there a way I can implement the same?
Right now I enumerate through the two arrays like so:
for (NSDictionary *eachPlayer in 1stArray) {
for (NSDictionary *eachPrediction in 2ndArray) {
if (eachPrediction[kId] != eachPlayer[kId]) {
[self.predictPlayerArray addObject:eachPlayer];
}
}
}
But this fails in the above case and adds both the values to the predictionPlayerArray - in the first iteration it adds 1 and in the forth iteration it adds 2. How do I prevent that from happening?
Thanks.
EDIT
I seem to have solved it this way. Not the best solution but it seems to be working:
for (NSDictionary *eachPlayer in arrayOne) {
for (NSDictionary *eachPrediction in arrayTwo) {
if (eachPrediction[kId] == eachPlayer[kId]) {
if ([self.predictPlayerArray containsObject:eachPlayer]) {
[self.predictPlayerArray removeObject:eachPlayer];
}
break;
}
else {
[self.predictPlayerArray addObject:eachPlayer];
}
self.predictPlayerArray = [self.predictPlayerArray valueForKeyPath:#"#distinctUnionOfObjects.self"];
}
}
Something like this should do:
NSArray *array1 = #[#{#"1":#"foo"},#{#"2":#"bar"},#{#"3":#"abc"}];
NSArray *array2 = #[#{#"2":#"abc"},#{#"1":#"abc"},#{#"4":#"foo"}];
NSMutableSet *result = [NSMutableSet new];
for (NSDictionary *dict1 in array1){
[dict1 enumerateKeysAndObjectsUsingBlock:^(id key1, id obj1, BOOL *stop1) {
for (NSDictionary *dict2 in array2) {
[dict2 enumerateKeysAndObjectsUsingBlock:^(id key2, id obj2, BOOL *stop2) {
if ([obj2 isEqual:obj1]){
[result addObject:#{key1:obj1}];
*stop2 = YES;
}
}];
}
}];
}
NSLog(#"result %#", result);
As you has nested dictionaries you should iterate also in them and finally store the result in a set that would prevent to have duplicate entries (if you use a NSMutableArray you will have twice {3:abc})
The log output is:
2015-02-03 13:53:07.897 test[19425:407184] result {(
{
1 = foo;
},
{
3 = abc;
}
)}
How to convert an array into a dictionary in Objective-C language?
This is the array:
[{"1":"2"}, {"2":"3"}]
But I want :
{"1":"2", "2":"3"}
Please help me, I am a new iPhone developer.
I am assuming that you want to combine an array of dictionaries into a single dictionary.
NSArray *array = #[#{#"1":#"2"},#{#"2":#"3"}];
NSMutableDictionary *result = [[NSMutableDictionary alloc]init];
for (NSDictionary *dict in array)
{
[result addEntriesFromDictionary:dict];
}
/*
result = {
1 = 2;
2 = 3;
}
*/
Where did your data come from? The easiest way to "convert" the above is to simply create a single dictionary in the first place.
Otherwise:
NSMutableDictionary* newDict = [NSMutableDictionary dictionary];
for (NSDictionary* oldDict in sourceArray) {
[newDict addEntriesFromDictionary:oldDict];
}
I'm trying to add an dictionary to an array to create an array on dictionaries, but when I test the app, the array is still empty. Take a look on my code:
NSMutableArray *listaEstabelecimentosPorCategoria;
for (NSDictionary *tempDict in listaEstabelecimentos) {
if ([[tempDict objectForKey:#"category"] integerValue] == 1) {
[listaEstabelecimentosPorCategoria addObject:tempDict];
NSLog(#"TEST");
}
}
NSLog(#"%#", listaEstabelecimentosPorCategoria);
The app prints this:
2013-08-18 12:16:38.802 Petrópolis[10157:c07] TEST
2013-08-18 12:16:38.802 Petrópolis[10157:c07] TEST
2013-08-18 12:16:38.803 Petrópolis[10157:c07] (null)
when I test the app, the array is still empty.
This is because you did not initialize listaEstabelecimentosPorCategoria:
NSMutableArray *listaEstabelecimentosPorCategoria = [NSMutableArray array];
NSMutableArray *listaEstabelecimentosPorCategoria=[[NSMutableArray alloc] init]; //initialize
for (NSDictionary *tempDict in listaEstabelecimentos) {
if ([[tempDict objectForKey:#"category"] integerValue] == 1) {
[listaEstabelecimentosPorCategoria addObject:tempDict];
NSLog(#"TEST");
}
}
NSLog(#"%#", listaEstabelecimentosPorCategoria);
NSMutableArray *listaEstabelecimentosPorCategoria this code hasn't been allocated to memory so it will be null value
NSMutableArray *listaEstabelecimentosPorCategoria = [NSMutableArray array];
then listaEstabelecimentosPorCategoria add the object.
We have an app that calls a SOAP web service and retrieves a long list of XML, which the app then parses into an NSArray of NSDictionary objects. The NSArray contains a list of Rental Apartment information, each of which is stored into an NSDictionary.
The entire list may contain 10 different types of Apartments (i.e. 2-room, 3-room), and we need to split the NSArray into smaller NSArrays based on Room-Type, which has the key "roomType" in the NSDictionary objects.
Currently our algorithm is
Use [NSArray valueForKeyPath:#"#distinctUnionofObjects.room-type"]
to obtain a list of unique room-type values.
Loop through the list of unique room-type values
For each unique room-type value, use NSPredicate to retrieve matching items from the Original list
Our code is below (renamed for clarity):
NSArray *arrOriginal = ... ...; // Contains the Parsed XML list
NSMutableArray *marrApartmentsByRoomType = [NSMutableArray arrayWithCapacity:10];
NSMutableArray *arrRoomTypes = [arrOriginal valueForKeyPath:#"distinctUnionOfObjects.roomType"];
for(NSString *strRoomType in arrRoomTypes) {
NSPredicate *predicateRoomType = [NSPredicate predicateWithFormat:#"roomType=%#", strRoomType];
NSArray *arrApartmentsThatMatchRoomType = [arrOriginal filteredArrayUsingPredicate:predicateRoomType]; // TAKES A LONG TIME EACH LOOP-ROUND
[marrApartmentsByRoomType addObject:arrApartmentsThatMatchRoomType];
}
However, step 3 is taking a long time as the original list may contain large amount (>100,000) of items. It seems that NSPredicate goes through the entire list for each key value. Is there a more efficient way of splitting a large NSArray into smaller NSArrays, based on NSDictionary keys?
If the order of your splited Arrays is not important, i have a solution for you:
NSArray *arrOriginal;
NSMutableDictionary *grouped = [[NSMutableDictionary alloc] initWithCapacity:arrOriginal.count];
for (NSDictionary *dict in arrOriginal) {
id key = [dict valueForKey:#"roomType"];
NSMutableArray *tmp = [grouped objectForKey:key];
if (tmp == nil) {
tmp = [[NSMutableArray alloc] init];
[grouped setObject:tmp forKey:key];
}
[tmp addObject:dict];
}
NSMutableArray *marrApartmentsByRoomType = [grouped allValues];
This is quite performant
- (NSDictionary *)groupObjectsInArray:(NSArray *)array byKey:(id <NSCopying> (^)(id item))keyForItemBlock
{
NSMutableDictionary *groupedItems = [NSMutableDictionary new];
for (id item in array) {
id <NSCopying> key = keyForItemBlock(item);
NSParameterAssert(key);
NSMutableArray *arrayForKey = groupedItems[key];
if (arrayForKey == nil) {
arrayForKey = [NSMutableArray new];
groupedItems[key] = arrayForKey;
}
[arrayForKey addObject:item];
}
return groupedItems;
}
Improving #Jonathan answer
Converting array to dictionary
Maintaining the same order as it was in original array
//only to a take unique keys. (key order should be maintained)
NSMutableArray *aMutableArray = [[NSMutableArray alloc]init];
NSMutableDictionary *dictFromArray = [NSMutableDictionary dictionary];
for (NSDictionary *eachDict in arrOriginal) {
//Collecting all unique key in order of initial array
NSString *eachKey = [eachDict objectForKey:#"roomType"];
if (![aMutableArray containsObject:eachKey]) {
[aMutableArray addObject:eachKey];
}
NSMutableArray *tmp = [grouped objectForKey:key];
tmp = [dictFromArray objectForKey:eachKey];
if (!tmp) {
tmp = [NSMutableArray array];
[dictFromArray setObject:tmp forKey:eachKey];
}
[tmp addObject:eachDict];
}
//NSLog(#"dictFromArray %#",dictFromArray);
//NSLog(#"Unique Keys :: %#",aMutableArray);
//Converting from dictionary to array again...
self.finalArray = [[NSMutableArray alloc]init];
for (NSString *uniqueKey in aMutableArray) {
NSDictionary *aUniqueKeyDict = #{#"groupKey":uniqueKey,#"featureValues":[dictFromArray objectForKey:uniqueKey]};
[self.finalArray addObject:aUniqueKeyDict];
}
Hope, It will help when client wants final array in same order as input array.
NSMutableDictionary *expense_ArrContents = [[NSMutableDictionary alloc]init];
for (int i = 1; i<=4; i++) {
NSMutableArray *current_row = [NSMutableArray arrayWithObjects:#"payer_id",#"Expense_Type_id",#"Category_Id",#"SubCategory_Id",nil];
[expense_ArrContents setObject:current_row forKey: [NSNumber numberWithInt:i]];
}
NSArray *newArray = [expense_ArrContents allKeysForObject:#"payer_id"];
NSLog(#"%#",[newArray description]);
i want to get the list of key values containing the particular object which is in the array of values stored in nsmutabledictionary for a particular key.
In the line where you get all the keys ([expense_ArrContents allKeysForObject:#"payer_id"];) you actually get keys for an object that is not in any of the array's items. This #"player_id" is different object than the #"player_id" you added in current_row. In fact, maybe all of your rows have different #"player_id" objects (except if the compiler has made some optimization - maybe it threats that same string literal as one object instead of creating new object for each iteration).
Try creating an NSString object for the #"player_id" which you add to the current_row and then get all the keys for that same object:
NSString* playerId = #"player_id";
for(){
NSMutableArray *current_row = [NSMutableArray arrayWithObjects: playerId,...];
...
}
NSArray *newArray = [expense_ArrContents allKeysForObject:playerId];
Your NSArray *newArray = [expense_ArrContents allKeysForObject:#"payer_id"]; will not return any value because in expense_ArrContents there is no such key(#"payer_id"), instead there are keys like 1,2,3 etc.What is your requirement?Want to see what all keys are there in expense_ArrContents just log
NSArray*keys=[expense_ArrContents allKeys];
Try this :
NSMutableArray *array_key=[[NSMutableArray alloc]init];
for (NSString *key in expense_ArrContents) {
if ([[expense_ArrContents objectForKey:key] containsObject:#"payer_id"]) {
[array_key addObject:key];
}
}