NSDictionary without sorting in iOS - ios

How to add and get the values from NSDictionary without key sorting?
NSDictionary is sorting the keys automatically.
How to get dictionary on added object format without sorting?
I have added the objects in below order.
NSDictionary *ScroesDic = [NSDictionary dictionaryWithObjectsAndKeys:#3,#"id_player",#100,#"shots[0][power]",#90,#"shots[0][precision]",#72,#"shots[1][power]",#27,#"shots[1][precision]",#23,#"shots[2][power]",#80,#"shots[2][precision]",#23,#"shots[3][power]",#80,#"shots[3][precision]",#23,#"shots[4][power]",#80,#"shots[4][precision]",#23,#"shots[5][power]",#80,#"shots[5][precision]",#23,#"shots[6][power]",#80,#"shots[6][precision]",#23,#"shots[7][power]",#80,#"shots[7][precision]",#23,#"shots[8][power]",#80,#"shots[8][precision]",#23,#"shots[9][power]",#80,#"shots[9][precision]",#23,#"shots[10][power]",#80,#"shots[10][precision]",#23,#"shots[11][power]",#80,#"shots[11][precision]",#23,#"shots[12][power]",#80,#"shots[12][precision]", nil];
NSLog(#"%#",ScroesDic);
But,the dictionary returns below order.
{
"id_player" = 3;
"shots[0][power]" = 100;
"shots[0][precision]" = 90;
"shots[10][power]" = 23;
"shots[10][precision]" = 80;
"shots[11][power]" = 23;
"shots[11][precision]" = 80;
"shots[12][power]" = 23;
"shots[12][precision]" = 80;
"shots[1][power]" = 72;
"shots[1][precision]" = 27;
"shots[2][power]" = 23;
"shots[2][precision]" = 80;
"shots[3][power]" = 23;
"shots[3][precision]" = 80;
"shots[4][power]" = 23;
"shots[4][precision]" = 80;
"shots[5][power]" = 23;
"shots[5][precision]" = 80;
"shots[6][power]" = 23;
"shots[6][precision]" = 80;
"shots[7][power]" = 23;
"shots[7][precision]" = 80;
"shots[8][power]" = 23;
"shots[8][precision]" = 80;
"shots[9][power]" = 23;
"shots[9][precision]" = 80;
}

NSDictionary is not meant to be sorted. You can get it sorted by getting all keys using allKeys and sorting that array to your liking. Then loop through this array and get the corresponding values.
Here is one way of doing it:
NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:#"key" ascending:YES comparator:^(id obj1, id obj2) {
if (obj1 > obj2) {
return (NSComparisonResult)NSOrderedDescending;
}
if (obj1 < obj2) {
return (NSComparisonResult)NSOrderedAscending;
}
return (NSComparisonResult)NSOrderedSame;
}];
NSArray *sortedKeys = [[filteredDictionary allKeys] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]];
NSMutableDictionary *orderedDictionary = [NSMutableDictionary dictionary];
for (NSString *index in sortedKeys) {
[orderedDictionary setObject:[filteredDictionary objectForKey:index] forKey:index];
}
filteredDictionary = orderedDictionary;
May it helps you.

Like an NSSet, the NSDictionary class represents an unordered
collection of objects; however, they associate each value with a key,
which acts like a label for the value.
You dont need to order the NSDictionary in anyway.That's make no sense. Because you are accessing the object by using the key not in any order.

By documentation, keys order in a NSDictionary is not defined:
allKeys
Returns a new array containing the dictionary’s keys.
(NSArray *)allKeys
Return Value
A new array containing the dictionary’s keys, or an empty array if the dictionary has no > entries.
Discussion
The order of the elements in the array is not defined.
If you want to keep a particular order of your keys, let's say the "insertion order" what you can do is subclass NSDictionary (difficult, as you should maintain the complex internal API coherent) or make a new class which contains internally a NSDictionary + NSArray to keep the insertion order of the keys, and then build a custom API similar to the NSDictionary one (but just a small subset of the methods you really need). E.g. of a mutable class:
#interface MyDictionary ()
#property (strong,nonatomic) NSMutableDictionary *internalDictionary;
#property (strong,nonatomic) NSMutableArray *internalArray;
#end
#implementation MyDictionary
-(id)init {
self = [super init];
if(self) {
_internalDictionary = [NSMutableDictionary new];
_internalArray = [NSMutableArray new];
}
}
-(void)setObject:(id)value forKey:(id)key {
_internalDictionary[key]=value;
// add key in array only if not already added yet
if(![_internalArray containsObject:key]) {
[_internalArray addObject:key];
}
}
#end

Related

Sort NSSet of custom objects by one attribute in Objective-C

I am trying to sort an array by the most common value of a property or attribute. This question and others suggest you can do this efficiently using an NSSet. However, it is merely sorting by most common string, not values of a property within custom objects. How would I get the following to return the most popular title?
NSArray<Articles*> *results = [self.managedObjectContext executeFetchRequest:fetchRequest
error:&error];
NSCountedSet* mySet = [[NSCountedSet alloc] initWithArray:results];
Articles* mostRead = nil;
NSUInteger highestCount = 0;
for(Articles* article in results) {
NSUInteger count = [mySet countForObject:article.title];
if(count > highestCount) {
highestCount = count;
mostRead = article;
}
}
The above code is not returning a value as countForObject:article.title does not seem to be recognized.
Your mySet if set of Articles *. Then you count for article. title which's NSString *. Try to changes to set of NSString * should work.
NSMutableArray<NSString *> *resultsStr = [NSMutableArray new];
[results enumerateObjectsUsingBlock:^(Articles * _Nonnull obj,
NSUInteger idx,
BOOL * _Nonnull stop) {
[resultsStr addObject:obj.title];
}];
NSCountedSet* mySet = [[NSCountedSet alloc] initWithArray:resultsStr];

ordering array with another array

I have the following categoryNames array.
And now, I have categoryTempElements and it has cName property. I need to know how to order categoryTempElements with a order of categoryNames.
UPDATE: I have added sortOrder property to Category object and tried the following but order does not change.
for (Category* a in categoryTempElements) {
int index = (int)[categoryNames indexOfObject:a.cName];
a.sortOrder = index;
}
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortOrder" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [categoryTempElements sortedArrayUsingDescriptors:sortDescriptors];
Another way could be without using sortedArrayUsingComparator, using two for-loops. Declare a new Mutable array called sortedCategoryElements and compare the categoryNames in categoryTempElements, If matches add it to a new array sortedCategoryElements:
NSMutableArray *sortedCategoryElements = [NSMutableArray new];
for (NSString *name in categoryNames) {
for (Category *category in categoryTempElements) {
if (name == category.cName) {
[sortedCategoryElements addObject:category];
break;
}
}
}
I tried with your set of data, it worked for me.
Hope it helps!
You need first convert your categoryNames array into dictionary with NSString key and NSNumber int value, the value will be the order in the array
//this is example code, this will be your first array (reference value array)
NSArray * array = #[#"prueba",#"prueba2",#"prueba3"];
//first you need convert this array in NSDictionary
NSMutableDictionary * arrayDict = [NSMutableDictionary dictionary];
int counter = 0;
for (NSString * value in array) {
if(arrayDict[value] == nil)
{
arrayDict[value] = [NSNumber numberWithInt:counter];
}
counter++;
}
After that then you can get the value and order with sortedArrayUsingComparator method, something like this
//this is an example of your second array categoryTempElements
NSArray * arrayOfObjs = #[[testObject testObjectWithName:#"prueba3"],[testObject testObjectWithName:#"prueba"],[testObject testObjectWithName:#"prueba2"]];
NSArray * sorted = [arrayOfObjs sortedArrayUsingComparator:^NSComparisonResult(testObject * _Nonnull obj1, testObject * _Nonnull obj2) {
if([((NSNumber*)arrayDict[obj1.cName]) intValue] < [((NSNumber*)arrayDict[obj2.cName]) intValue]){
return NSOrderedAscending;
}
if([((NSNumber*)arrayDict[obj1.cName]) intValue] > [((NSNumber*)arrayDict[obj2.cName]) intValue]){
return NSOrderedDescending;
}
return NSOrderedSame;
}];
for (testObject * obj in sorted) {
NSLog(#"%#",obj.cName);
}
And voila in sorted you will have your array of object sorted by your first array NSString order
Hope this helps
Create a dictionary with cName as the key and the Category object as the value. Then iterate over the categoryNames array, and build another array by using each item in categoryNames as the key. The resulting array should be sorted in the same order as categoryNames.
NSArray has a method sortedArrayUsingComparator: which sorts an array using the ordering implemented by the block you pass. This block, of type NSComparator, is passed references to two elements of your array and you must return the order of those two elements.
And now, I have categoryTempElements and it has cName property.
So your block will be passed two categoryTempElements, you need to access the cName property of each, and compare the resulting two values...
I need to know how to order categoryTempElements with a order of categoryNames
by the position, i.e. the index, of those values in your categoryNames array. The method indexOfObject: provides that index for you.
So put that together and your problem is solved.
HTH

How to find two NSArray has common NSDictionary

I have an NSArray. It has one or more NSDictionary. otherContacts has one dictionary in each index. chatContacts has two dictionary in each index. How can i find both Array has same contact_detail.
NSArray * otherContacts = {
"contact_detail" = {
"contact_Label" = "Test 5 ";
userid = 48;
};
}
NSArray * chatContacts ={
"contact_detail" = {
"contact_Label" = "Test 5 ";
userid = 48;
};
"last_msg_details" = {
"Key_from_me" = 1;
data = " B";
};
}
I have tried like this using NSPredicate. But Its not returning the common data.
NSArray *filtered = [otherContacts filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
return [chatContacts containsObject:evaluatedObject];
}]];
May be you can use NSMutableSet to accomplish that:
Like,
NSMutableSet* set1 = [NSMutableSet setWithArray:array1];
NSMutableSet* set2 = [NSMutableSet setWithArray:array2];
//Find intersect: Which will give common objects
[set1 intersectSet:set2];
//Array with common objects
NSArray* arrCommon = [set1 allObjects];
//Now check common objects count to find if it has common object
if(arrCommon.count>0){
//has common dictionary
}

Search element in nsdictionary by value

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
}
}

ios - convert NSArray to NSDictionary

i want to convert an nsarray to nsdictionary i'm using to
- (NSDictionary *) indexKeyedDictionaryFromArray:(NSArray *)array
{
id objectInstance;
NSUInteger indexKey = 0;
NSMutableDictionary *mutableDictionary = [[NSMutableDictionary alloc] init];
for (objectInstance in array)
[mutableDictionary setObject:objectInstance forKey:[NSNumber numberWithUnsignedInt:indexKey++]];
return (NSDictionary *)[mutableDictionary autorelease];
}
output result is:
{
0 = {
Event = "";
ID = 1; };
3 = {
Event = "";
ID = 77; };
2 = {
Event = "";
ID = 23; };
1 = {
Event = "";
ID = 45; };
7 = {
Event = "";
ID = 10; };
5 = {
Event = "";
ID = 26; };
6 = {
Event = "";
ID = 27;
};
8 = {
Event = "";
ID = 28;
};
}
After convert to nsdictionary, the order of nsdictionary isn't true to the original order, i want to display the same order in nsarray, i don't know how? can you help me?
NSDictionary does not have an order. Sort the keys and use them to access the entries.
If I understand correctly from your responses to #ACB and #Zaph in the comments, you want to do the following:
Maintain a collection mapping integer keys to object values which is ordered by the keys.
If I'm understanding correctly, an array won't be good enough for your purposes because the integer keys in an array allow for no "holes". You, however, need to allow for holes: in the output in your question, the key-value pair for 4 is missing. For this reason, a dictionary is appealing to you.
Unfortunately, a dictionary will not allow you to maintain an ordering on the key-value pairs it contains, as #Zaph points out. You say, however, you just want to display the values in the dictionary ordered by the keys in a UITableView. Presumably, it is unimportant the order in which the dictionary is serialized to disk (using writeToFile:atomically:) so long as the contents of the dictionary are displayed in the correct order in the table view.
A dictionary can be used for this purpose as follows. First, we'll need a class PFXKeyValuePair;
#interface PFXKeyValuePair : NSObject
#property (nonatomic) id<NSCopying> key;
#property (nonatomic) id value;
+ (PFXKeyValuePair *)pairWithValue:(id)value forKey:(id<NSCopying>)key;
+ (NSArray *)pairsWithValues:(NSArray *)values forKeys:(NSArray *)keys;
#end
#implementation PFXKeyValuePair
+ (PFXKeyValuePair *)pairWithValue:(id)value forKey:(id<NSCopying>)key
{
PFXKeyValuePair *pair = [[PFXKeyValuePair alloc] init];
pair.value = value;
pair.key = key;
return pair;
}
+ (NSArray *)pairsWithValues:(NSArray *)values forKeys:(NSArray *)keys
{
NSAssert(values.count == keys.count, #"The array of values must be the same size as the array of keys.");
NSUInteger count = values.count;
NSMutableArray *mutableRes = [NSMutableArray array];
for (NSUInteger index = 0; index < count; index++) {
PFXKeyValuePair *pair = [PFXKeyValuePair pairWithValue:values[index] forKey:keys[index]];
[mutableRes addObject:pair];
}
return [mutableRes copy];
}
#end
Second, we'll need a category method on NSDictionary:
#interface NSDictionary (PFXAdditions)
- (NSArray *)pfx_keyValuePairsSortedByKeyUsingComparator:(NSComparator)comparator;
#end
#implementation NSDictionary (PFXAdditions)
- (NSArray *)pfx_keyValuePairsSortedByKeyUsingComparator:(NSComparator)comparator
{
NSArray *sortedKeys = [self.allKeys sortedArrayUsingComparator:comparator];
NSArray *sortedValues = [self objectsForKeys:sortedKeys notFoundMarker:[NSNull null]];
return [PFXKeyValuePair pairsWithValues:sortedValues forKeys:sortedKeys];
}
#end
Note: In the above, PFX and pfx are placeholders. You ought to replace them with prefixes appropriate to your project.
We can then use this category method when to populate our UITableView. Let's say we have a property
#property (nonatomic) NSDictionary *events;
And let's assume that the table view has only one section in which these events will be shown.
Then we can implement –tableView:numberOfRowsInSection: in our UITableViewController subclass as follows:
– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.events.count;
}
And within our implementation of –tableView:numberOfRowsInSection: we can determine the appropriate entry in the dictionary to use as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//...
NSArray *pairs = [self.events pfx_keyValuePairsSortedByKeyUsingComparator:^(id obj1, id obj2) {
NSNumber *key1 = (NSNumber *)obj1;
NSNumber *key2 = (NSNumber *)obj2;
return [key1 compare:key2];
}];
NSUInteger index = [indexPath indexAtPosition:1];
PFXKeyValuePair *pair = pairs[index];
/*
At this point, pair.value will be a dictionary as in your output above
holding a value for the key #"Event" and a value for the key #"ID".
*/
//...
}
This could be made faster by making pairs a property and only computing it when necessary (for example, by only computing pairs just prior to reloading the table's data).
Note: Using this approach, the dictionary will still not be serialized to disk (when calling -writeToDisk:atomically:) "in order" and your output will still look the same as in your question. However, this does not matter: when the data is displayed to the user in the table view, the data will be ordered as you're hoping.
This is example one of the exmple get the emplyee list NSMutableArray and create NSMutableDictionary.......
NSMutableArray *emloyees = [[NSMutableArray alloc]initWithObjects:#"saman",#"Ruchira",#"Rukshan",#"ishan",#"Harsha",#"Ghihan",#"Lakmali",#"Dasuni", nil];
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
for (NSString *word in emloyees) {
NSString *firstLetter = [[word substringToIndex:1] uppercaseString];
letterList = [dict objectForKey:firstLetter];
if (!letterList) {
letterList = [NSMutableArray array];
[dict setObject:letterList forKey:firstLetter];
}
[letterList addObject:word];}NSLog(#"dic %#",dict);

Resources