I have a simple UITableView, when users adds new rows, these will be added to the NSMutableDictionary. I can retrieve the values for a specific key.
NSArray *myArr = [myDictionary valueForKey:#"Food"];
This will show me all values for key food, this is an example of my NSLog:
(
burger,
pasta )
If I add more objects to myDictionary but for a different key, for example:
NSArray *drinks = [NSArray arrayWithObjects:#"cola",#"sprite",nil];
[myDictionary setObject:drinks forKey:#"Drink"];
I can't retrieve all values using the following code:
NSArray *allMenu = [myDictionary allValues];
It shows me the following NSLog:
(
(
burger,
past
),
(
cola,
sprite
) )
I don't know where is the problem. Why I can't get all values from NSDictionary to NSArray.
If I use the code:
NSArray *allMenu = [[myDictionary allValues] objectAtIndex:0];
will show me the Food values. If I change objectAtIndex to 1 will show me the Drink value.
I am not entirely sure what you are asking, if you are trying to print all of the values within an NSDictionary do the following:
//Gets an array of all keys within the dictionary
NSArray dictionaryKeys = [myDictionary allKeys];
for (NSString *key in dictionaryKeys)
{
//Prints this key
NSLog(#"Key = %#", key);
//Loops through the values for the aforementioned key
for (NSString *value in [myDictionary valueForKey:key])
{
//Prints individual values out of the NSArray for the key
NSLog(#"Value = %#", value);
}
}
You can do this in one line by flattening the returned 2-dimensional array by using key value coding (KVC). I found this in another answer, see the docs. In your case, it looks as follows:
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionary];
NSArray *food = [NSArray arrayWithObjects:#"burger",#"pasta",nil];
[myDictionary setObject:food forKey:#"Food"];
NSArray *drinks = [NSArray arrayWithObjects:#"cola",#"sprite",nil];
[myDictionary setObject:drinks forKey:#"Drink"];
NSArray *allMenue = [[myDictionary allValues] valueForKeyPath:#"#unionOfArrays.self"];
Try this Solution :
- (NSDictionary *) indexKeyedDictionaryFromArray:(NSArray *)array
{
id objectInstance;
NSUInteger indexKey = 0U;
for (objectInstance in myArr)
[mutableDictionary setObject:objectInstance forKey:[NSNumber numberWithUnsignedInt:indexKey++]];
return (NSDictionary *)[myDictionary autorelease];
}
Related
This question already has answers here:
sort NSDictionary values by key alphabetical order
(4 answers)
Closed 6 years ago.
I have a dictionary in which, for a single key(for example key "0") there are a key value pair data.The keys are like name, id,p_id. I want to sort the NSMutableDictionary for the values related to the Key "name". The data in the dictionary is as follows,
0 = {
id = 12;
name = "Accounts ";
"p_id" = 13222071;
};
1 = {
id = 13;
name = "consultant";
"p_id" = 15121211;
};
2 = {
id = 11;
name = "Tania";
"p_id" = 10215921;
};
}
Any help is appreciated!
Please try out the below code:
[yourMutableArray sortUsingComparator: (NSComparator)^(NSDictionary *a, NSDictionary *b) {
NSString *key1 = [a objectForKey: #"name"];
NSString *key2 = [b objectForKey: #"name"];
return [key1 compare: key2];
}];
NSLog(#"Sorted Array By name key : %#", yourMutableArray);
Hope this helps!
NSArray *sortedKeys = [dict.allKeys sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *d1, NSDictionary *d2) {
return [d1[#"name"] compare:d2[#"name"]];
}];
NSArray *objects = [dict objectsForKeys:sortedKeys notFoundMarker:[NSNull null]];
Dictionaries are not sorted, and doesn't resemble any order. What you should do is to getAll the keys first. Then apply a sort method on the keys, then request the objects according to the ordered keys.
E.g:
NSArray *keys = [dictionary allKeys];
NSArray *sortedKeys = <sort the keys according to your preferred method>
Now you can iterate the Dictionary from the order of the array sortedKeys.
While it has been made abundantly clear that Dictionaries can't be sorted and rightfully so, that does not mean the ends you are aiming for can't be achieved. This code will do that for you:
NSArray *arrayOfDicts = dic.allValues; //Now we got all the values. Each value itself is a dictionary so what we get here is an array of dictionaries
NSSortDescriptor *nameDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:YES]; //Create sort descriptor for key name
NSArray *sortingDesc = [NSArray arrayWithObject:nameDescriptor];
NSArray *sortedArray = [arrayOfDicts sortedArrayUsingDescriptors:sortingDesc]; //Get sorted array based on name
NSMutableDictionary *kindaSortedDict = [[NSMutableDictionary alloc] init];
int keyForDict=0;
for(NSDictionary *valDict in sortedArray)
{
[kindaSortedDict setObject:valDict forKey:[NSString stringWithFormat:#"%i",keyForDict]]; //Set values to our new dic which will be kind of sorted as the keys will be assigned to right objects
keyForDict++;
}
//Now you can simply get sorted array of keys from kindaSortedDic and results for them will always be sorted alphabetically. Alternatively you can just skip all that bother and directly use sortedArray
I have added comments in code to help you understand that.
For accessing sorted values I'd do this:
NSArray *sortedKeys = [kindaSortedDict.allKeys sortedArrayUsingDescriptors:
#[[NSSortDescriptor sortDescriptorWithKey:#"intValue"
ascending:YES]]];
for(NSString *key in sortedKeys)
{
NSDictionary *valDict = [kindaSortedDict objectForKey: key];
NSLog(#"Dict is: %# for key: %#",valDict,key);
}
I have a JSON array being pulled into XCode with a key and value. I can get the keys. I can get the values. But is there an easy way to combine them into a single array?
The following code works, but I end up with two separate arrays (channels and channelKeys).
This seems like an inelegant way to create a single array which contains both the key and its value.
-(void) convertArray : (NSMutableArray *)data{
// Set data
NSMutableDictionary *dic = [data objectAtIndex:0];
for (NSString *key in [dic allKeys]) {
[channels addObject:[dic objectForKey:key]];
}
// Set Key Array
NSMutableDictionary *dic3 = [data objectAtIndex:0];
NSArray *keys = [dic3 allKeys];
[channelKeys addObjectsFromArray: keys];
}
If you are trying to create an array of the form [key1, value1, key2, value2, key3, value3...] then try something like the following (recall that keys are not restricted to NSStrings)
for (id key in [dic allKeys]) {
[resultArray addObject:key];
[resultArray addObject:[dic objectForKey:key]];
}
I have nsdictionary which contains elements with following structure
name --> value
email--> key
I get value(of above structure) from user,
now I want to search element in nsdictionary by value(entered by user) not by key, whether it is present in nsdictionary or not and also want to get index of that element if present.
How to do this?
The best to do so would propably be
- (NSArray *)allKeysForObject:(id)anObject
This method of NSDictionary gives you back all the keys having anObject as their value. If you only have each object once in the whole dictionary it will logically return an array with only one key in it.
NSArray * users = ...; //your array of NSDictionary objects
NSPredicate *filter = [NSPredicate predicateWithFormat:#"email = test#gmail.com"];
NSArray *filteredContacts = [contacts filteredArrayUsingPredicate:filter];
for more than one value of email, then use an OR in the predicate:
filter = [NSPredicate predicateWithFormat:#"contact_type = 42 OR contact_type = 23"];
The dictionary data structure has no 'order', so you'd have to search for your key by iterating the collection and looking for the desired value.
Example:
NSString *targetKey = nil;
NSArray *allKeys = [collection allKeys];
for (int i = 0; i < [allKeys count]; ++i) {
NSString *key = [allKeys objectAtIndex:i];
NSString *obj = [collection objectForKey:key];
if ([obj isEqualToString:searchedString]) { // searchedString is what you're looking for
targetKey = key;
break;
}
}
// check if key was found (not nil) & proceed
// ...
You can search the entered value in NSDictionary , but you can't get an index of value , as NSDictionary has no order of key value pair.
NSArray *array = [yourDictionaryObject allValues];
if ([array containsObject:#"userEnteredValue"]) {
<#statements#>
}
You need to iterate through the Dictionary for the keys has the Value of your need:
Try this:
NSArray *keys= [json allKeys];
for (NSString *keysV in keys){
NSLog(#"Keys are %#", keysV);
if([Your_Dict objectForKey: keysV] isEqual:#"string to Match"){
//Do your stuff here
}
}
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];
}
}