Sorting NSDictionary - objective-c

I was wondering if someone can show me how to sort an NSDictionary; I want to read it starting from the last entry, since the key is Date + Time and I want to be able to append it to an NSMutableString. I was able to read it using an enumerator but I don't get the results I want.
Thanks

For your requirements the easiest way is to create a new array from the keys, sort that, then use the array to reference items from the original dictionary.
(Note myComparison is your own method that will compare two keys).
NSMutableArray* tempArray = [NSMutableArray arrayWithArray:[myDict allKeys]];
[tempArray sortedArrayUsingSelector:#selector(myComparison:)];
for (Foo* f in tempArray)
{
Value* val = [myDict objectForKey:f];
}

I've aggregated some of the other suggestions on StackOverflow on sorting an NSDictionary into something very compact that will sort alphabetically. I have a Plist file in 'path' that I load in to memory and want to dump.
NSDictionary *glossary = [NSDictionary dictionaryWithContentsOfFile: path];
NSArray *array1 = [[glossary allKeys] sortedArrayUsingDescriptors:#[ [NSSortDescriptor sortDescriptorWithKey:#"" ascending:YES selector:#selector(localizedStandardCompare:)] ]];
for ( int i=0; i<array1.count; i++)
{
NSString* key = [array1 objectAtIndex:i];
NSString* value = [glossary objectForKey:key];
NSLog(#"Key=%#, Value=%#", key, value );
}

Related

Inserting NSDictionary into sorted NSMutableArray

I want to insert an NSDictionary object into an array and have the array sorted by objectForKey.
I managed to do this by inserting, re-sorting and reloading the array, which works fine, but I figured there would be a better method, which there is, I just don't know how to use it.
Current code:
-(NSMutableArray*)sortArray:(NSMutableArray*)theArray {
return [[theArray sortedArrayUsingDescriptors:[NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:#"n"
ascending:YES]]] mutableCopy];
}
returns the re-sorted array. Fine. Works perfectly, but... is it the most efficient?
From another question I gather that this is the method to use to find the index to insert into:
NSUInteger newIndex = [array indexOfObject:newObject
inSortedRange:(NSRange){0, [array count]}
options:NSBinarySearchingInsertionIndex
usingComparator:comparator];
[array insertObject:newObject atIndex:newIndex];
The problem is I have no idea how to use the comparator method, and if that's even possible when I want to sort by objectForKey for each index.
Can anyone exemplify the above method when the key of the object (newObject in above example) to sort by is, let's say:
[newObject objectForKey:#"sortByThis"];
Use NSSortDescriptor
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"sortByThisKey" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray = [myArray sortedArrayUsingDescriptors:sortDescriptors];
here is the simple example for comparator
- (NSComparisonResult)compareResulst:(CustomObject *)otherObject {
if(self.name isEqualToString:key)
{
return NSOrderedAscending;
}
else
{
return NSOrderedDescending
}
}
NSArray *sArray;
sArray = [unsArray sortedArrayUsingSelector:#selector(compareResulst:)];
this will sort the array. it will iterate through object and based on your if else it will move object up and down ...
Here's an example of sorting
//For make a we're adding 5 random integers into array inform of NSDictionary
//here, we're taking "someKey" to store the integer (converted to string object) into dictionary
NSMutableArray *array = [NSMutableArray array];
for(int i = 1; i<=5; i++) {
[array addObject:[NSDictionary dictionaryWithObject:[#(arc4random()%10) stringValue] forKey:#"someKey"]];
}
//create a sort descriptor to sort the array
//give the key in dictionary for which you want to perform sort
NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:#"someKey" ascending:YES];
//we're doing self sort for mutable array, & that's it, you'll have a sorted array.
[array sortUsingDescriptors:#[sort]];
N.B.
1.Instead of "someKey" from above example you can set any key for which you want to perform sort.
2.There's some other methods for sorting, you can use the one base on your requirement.
3.see #[sort] in code. Its full version is, [NSArray arrayWithObject:sort];

Sorting JSON Data by date

Hi I'm getting data online from a JSON file and I'm trying to sort it by date in descending order, I've done it before using an XML parser using an RSS feed and tried to use the same concept but can't seem to get it and it crashes every time.
NSData *data = [NSData dataWithContentsOfURL:url];
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSDictionary *dataDict = [dict objectForKey:#"data"];
NSArray *array = [dataDict objectForKey:#"items"];
for (int i=0; i<[array count]; i++) {
SongInfo *song = [[SongInfo alloc]init];
NSMutableDictionary *entry = [array objectAtIndex:i];
song.uploaded = [entry objectForKey:#"uploaded"];
song.uploader = [entry objectForKey:#"uploader"];
NSComparator comparator = ^(NSDictionary *a, NSDictionary *b) {
return [a[#"uploaded"] compare:b[#"uploaded"]];
};
NSUInteger index = [songsArray indexOfObject:entry
inSortedRange:NSMakeRange(0, [songsArray count])
options:NSBinarySearchingInsertionIndex
usingComparator:comparator];
[songsArray insertObject:song atIndex:index];
EDIT: Managed to fix it by using the NSSortDescriptor and putting it into an array and then back into the same array, not sure if there is a better way to do this but this is how I did it...
NSSortDescriptor *sortDescriptor;
sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"uploaded"
ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedArray;
sortedArray = [songsArray sortedArrayUsingDescriptors:sortDescriptors];
songsArray = [NSMutableArray arrayWithArray:sortedArray];
// [songsArray addObject:[song copy] atIndex:index];
[songsArray addObject:song];
You're comparing objects inserted in the songsArray with a comparator that takes in two dictionaries. It seems like the comparator should compare SongInfo objects rather than NSDictionaries.
We can't see what songsArray is. Creating a sorted array manually like you do is really inefficient. Call the NSArray method sortedArrayUsingComparator instead, and there is no need to create SongInfo objects.
On the other hand, if an array of SongInfo* is what you want, create that array first as an NSMutableArray with all the SongInfo's from the JSON data, then sort that array by calling sortUsingComparator.
Note that in the comparator block you can actually use the type of the object: So in the first case NSDictionary* instead of id, in the second case SongInfo* instead of id.

NSString parsing for specific values

I have an NSString that returns a list of values like this:
test_1=value_1
test/2=value_2
test3=value_3 value_4
test_4=value_5/value_6
...
More realistic result values:
inameX=vlan2
hname=server
lanipaddr=192.168.1.1
lannetmask=255.255.255.0
islan=0
islwan=0
dhcplease=604800
dhcplease_1=302400
ct_tcp_timeout=0 1200 40 30 60 60 5 30 15 0
ct_timeout=10 10
ct_udp_timeout=25 60
ctf_disable=1
ddnsx0=
cifs2=0<\\192.168.1.5
and so on...
If I do:
for (id key in dict) {
NSLog(#"key: %#, value: %#", [dict objectForKey:key], key);
}
it outputs:
key: inameX, value: vlan2
key: hname value: server
key: lanipaddr value: 192.168.1.1
key: lannetmask value: 255.255.255.0
This list is stored in one NSString *result. Not sure if I should put it in an array for this but I need to be able to call a function or command that will return a specific value_X based on the argument to match the variable. For example, get value of test_1 variable then it would return value_1. Or get test_4 then it would return value_5/value_6
Any idea how I can do that?
I appreciate your help. Thanks!
You probably want the method in NSString called componentsSeparatedByCharactersInSet: to split up that one string into an array. Since your values are separated by '=' and new line characters ('\n'), you want the set to include those two characters:
NSArray *strings = [NSString componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:#"=\n"]];
And then you can make this into a dictionary with NSDictoinary's dictionaryWithObjects: AndKeys: But first, you need to split that array into two arrays; one with objects, one with keys:
NSMutableArray *keys = [NSMutableArray new];
NSMutableArray *values = [NSMutableArray new];
for (int i = 0; i < strings.count; i++) {
if (i % 2 == 0) { // if i is even
[keys addObject:strings[i]];
}
else {
[values addObject:strings[i]];
}
}
Then you put them into an NSDictonary
NSDictionary *dict = [NSDictionary dictionaryWithObjects:values forKeys:keys];
NSLog(#"%#", dict[#"test_1"]) // This should print out 'value_1'
Hope that helps!
Use an NSDicationary. NSDictionaries are key value stores. In other words, there are a list of keys. Each key is unique. Each key has an associated value. The value can be any data type and the key has to conform to the NSCopying protocol (typically an NSString). If you try to access the value for a key that doesn't exist in your NSDictionary, the return value will be nil.
//create the dictionary and populate it
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"value_1" forKey:#"key_1"];
[dict setObject:#"value_2" forKey:#"key_2"];
[dict setObject:#"value_3" forKey:#"key_3"];
[dict setObject:#"value_4" forKey:#"key_4"];
NSString *stringInput = [self getStringInput];//however you find out your input
//find your string value based on the key passed in
NSString *strValue = [dict objectForKey:stringInput];
You can use a NSScanner to make this work.
Scan for the string for which you want the value, and then scan the string until you encounter \n and then use it for your requirement.
NSScanner *scan =[NSScanner scannerWithString:theString];
[scan scanString:keyString inToString:nil];
[scan setScanLocation:[scan scanLocation]+1];
[scan scanString:#"\n" inToString:requiredString];
So requiredString is the string which you want.

Sort 2 arrays? Objective-c [duplicate]

I have several arrays that need to be sorted side by side.
For example, the first array has names: #[#"Joe", #"Anna", #"Michael", #"Kim"], and
and the other array holds addresses: #[#"Hollywood bld", #"Some street 3", #"That other street", #"country road"], where the arrays' indexes go together. "Joe" lives at "Hollywood bld" and so on.
I would like to sort the names array alphabetically, and then have the address array sorted alongside so they still go together, with "Hollywood bld" having same index as "Joe". I know how to sort one array alphabetical with
NSSortDescriptor *sort=[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:NO];
[myArray sortUsingDescriptors:[NSArray arrayWithObject:sort]];
But is there any easy way of getting the second array sorted using the appropriate order?
Create a permutation array, initially set to p[i]=i
Sort the permutation according to the name key of the first array
Use the permutation to re-order both arrays
Example: let's say the first array is {"quick", "brown", "fox"}. The permutation starts as {0, 1, 2}, and becomes {1, 2, 0} after the sort. Now you can go through the permutation array, and re-order the original array and the second array as needed.
NSArray *first = [NSArray arrayWithObjects: #"quick", #"brown", #"fox", #"jumps", nil];
NSArray *second = [NSArray arrayWithObjects: #"jack", #"loves", #"my", #"sphinx", nil];
NSMutableArray *p = [NSMutableArray arrayWithCapacity:first.count];
for (NSUInteger i = 0 ; i != first.count ; i++) {
[p addObject:[NSNumber numberWithInteger:i]];
}
[p sortWithOptions:0 usingComparator:^NSComparisonResult(id obj1, id obj2) {
// Modify this to use [first objectAtIndex:[obj1 intValue]].name property
NSString *lhs = [first objectAtIndex:[obj1 intValue]];
// Same goes for the next line: use the name
NSString *rhs = [first objectAtIndex:[obj2 intValue]];
return [lhs compare:rhs];
}];
NSMutableArray *sortedFirst = [NSMutableArray arrayWithCapacity:first.count];
NSMutableArray *sortedSecond = [NSMutableArray arrayWithCapacity:first.count];
[p enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
NSUInteger pos = [obj intValue];
[sortedFirst addObject:[first objectAtIndex:pos]];
[sortedSecond addObject:[second objectAtIndex:pos]];
}];
NSLog(#"%#", sortedFirst);
NSLog(#"%#", sortedSecond);
First off, you might want to re-consider an architecture that requires you to sort two arrays in a parallel fashion like this. But having said that, you can do it by creating a temporary array of dictionaries that keep the elements of the two arrays paired.
Then you sort the combined array, and extract the two arrays again, sorted as requested:
Original data:
NSArray *names = #[#"Joe", #"Anna", #"Michael"];
NSArray *addresses = #[#"Hollywood bld", #"Some street 3", #"That other street"];
The actual sorting code:
NSMutableArray *combined = [NSMutableArray array];
for (NSUInteger i = 0; i < names.count; i++) {
[combined addObject: #{#"name" : names[i], #"address": addresses[i]}];
}
[combined sortUsingDescriptors:#[[NSSortDescriptor sortDescriptorWithKey:#"name" ascending:YES]]];
names = [combined valueForKey:#"name"];
addresses = [combined valueForKey:#"address"];
Notice that valueForKey: used on an array extracts a new array with the same size, populated with the properties of the objects in the original array. In this case, it create new arrays from the original ones, sorted as wanted.
This approach only requires a few lines of code and is easy to follow and debug, if needed.
The best way is to restructure your data so that you only have one array. In your example, it would make most sense to create a new class with both name and address, put those in an array and sort it by name.
You could probably do this by keeping track of indexes of objects before and after the sort but maybe it would be easier having a single object which hass all of these properties
Person : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *addresss;
Then you store these objects into a single array which you can sort by name, or address key paths

Creating an NSDictionary from an NSArray (Objective-c 2.0)

I have an NSArray containing n elements at indices 0, 1 ... n-1. I want to populate an NSDictionary with the contents of my array.
Specifically the dictionary should contain key-value pairs where the key is the hash of the ith element in the array and the value is the index into the array.
For example: array = [123, 101, 199] then the dictionary will contain three key-value pairs:
([123 hash], 0)
([199 hash], 2)
([101 hash], 1)
I've done this with a for loop over the array. What's a more concise way to do this? Perhaps something from NSKeyValueCoding?
More info: I'm thinking of something like this:
NSArray *keys = [myArray valueForKey:#"hash"];
NSArray *values = [myArray valueForKey:#"index"]; // #"index" needs to change
NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:values
forKeys:keys];
I would probably use something like David's for loop solution myself, but just for kicks, and because I'm still trying to wrap my head completely around them, I came up with a solution using blocks:
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:[array count]];
[array enumerateObjectsUsingBlock:^ (id obj, NSUInteger idx, BOOL *stop) {
[dict setObject:[NSNumber numberWithUnsignedLong:idx] forKey:hashFor(obj)]; } ];
I'm assuming the existence of a function hashFor that generates the hash. You can replace that part with a message to obj or whatever you do to generate the hash.
A for loop is pretty good, especially if you need the index. Otherwise you might use fast enumeration:
int i = 0;
for (object in array) {
… [NSNumber numberWithInt: i] … // Add to dict
i++;
}
This has nothing to do with KVC.