I have an array of strings like such:
NSArray *unsortedArray = [NSArray arrayWithObjects:#"MailIn", #"Branch", #"eSign", #"RDC", nil];
I receive this array and it is not gauranteed that all 4 strings will be present. It could have all 4, or only 1.
I need to sort the array in this exact order all the time.. [eSign, RDC, Branch, MailIn]. Keep in mind that there is a chance where one or more of these may not be present. How do I achieve this?? Any help would be greatly appreciated. Thanks in advance!
If you really want a sort then here is a way to do that. But for only 4 strings I'd likely just unroll #Zev Eisenberg's loop and build it up in code.
NSDictionary* indexes = #{ #"eSign" : #0, #"RDC" : #1, #"Branch" : #2, #"MailIn" : #3 };
NSArray* sorted = [unsorted sortedArrayUsingComparator: ^NSComparisonResult(NSString* s1, NSString* s2) {
return [indexes[s1] compare: indexes[s2]];
}];
I would build a new array, using the exemplar array as a template:
NSArray *exemplarArray = #[ #"eSign", #"RDC", #"Branch", #"MailIn" ];
NSArray *unsorted = #[ #"MailIn", #"Branch", #"eSign", #"RDC" ];
NSMutableArray *sorted = [NSMutableArray array];
for (NSString *string in exemplarArray) {
if ([unsorted containsObject:string]) {
[sorted addObject:string];
}
}
NSLog(#"%#", sorted);
Related
This code:
server_response = [{id:1},{id:2},{id:3},{id:4}]
I am getting above response from server now I want only the list of ids in one array like
ids = [1,2,3,4];
I know we can do by for loop but it takes long time if thousand of ids inside the response array.
Is there any better way to achieve above equation?
NSArray *result = [yourArray valueForKey:#"id"]
From the documentation for NSArray instance method valueForKey:
Returns an array containing the results of invoking valueForKey: using key on each of the array's objects
NSMutableArray *resultArray = [NSMutableArray array];
for (NSDictionary *dict in server_response) {
[resultArray addObject:[dict objectForKey:#"id"]];
}
Try above code. Hope it will help you. Result array has final values
NSArray *server_response = #[#{#"id":#"1"},#{#"id":#"2"},#{#"id":#"3"},#{#"id":#"4"}];
NSMutableArray *resultArray = [NSMutableArray array];
NSString *birdtemp;
for (NSDictionary *object in server_response) {
birdtemp = object[#"id"];
[resultArray addObject:birdtemp];
}
NSLog(#"%#",resultArray);
OutPut: [
1,
2,
3,
4
]
I need help with the following:
I have an NSArray with NSStrings, I want to loop thru these strings and find a matching string, when match is found the strings after this match will be extracted into an NSDictionary until a certain other match is hit.
Here is an example:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
So I want to loop thru this array and split it in 2 arrays one for fruit and one for vegetable.
Anyone can help with the logic?
Thanks
This is probably the simplest way to solve the problem:
NSArray *array = #[#"Chair",#"Fruit",#"Apple",#"Orange",#"Vegetable",#"Tomato",#"Fruit",#"Banana",#"Vegetable",#"Cucumber"];
NSMutableArray *fruitArray = [NSMutableArray array];
NSMutableArray *vegetableArray = [NSMutableArray array];
NSMutableArray *currentTarget = nil;
for (NSString *item in array)
{
if ([item isEqualToString: #"Fruit"])
{
currentTarget = fruitArray;
}
else if ([item isEqualToString: #"Vegetable"])
{
currentTarget = vegetableArray;
}
else
{
[currentTarget addObject: item];
}
}
In one iteration over the array, you just keep adding items to a result array using a pointer to one of two result arrays according to the last occurrence of the #"Fruit" or #"Vegetable" string.
This algorithm ignores all items before the first occurrence of the #"Fruit" or #"Vegetable" string, because the currentTarget is initialized to nil, which ignores the addObject: messages. If you want different behaviour, just change the initialization.
You said you wanted the results in a NSDictionary, but didn't specify what should be the key. If you want one NSDictionary with two keys, Fruit and Vegetable, and values NSArrays containing the items, just use the arrays previously created:
NSDictionary *dict = #{ #"Fruit": fruitArray, #"Vegetable": vegetableArray };
PS: You have a typo in your example, Vegtable instead of Vegetable. I corrected it in my code, so keep it in mind.
If I completely understand you:
NSArray *array = #[#"Fruit",#"Apple",#"Vegtable",#"Tomato",#"Fruit",#"Banana",#"Vegtable",#"Cucumber"];
NSMutableArray *fruits = [NSMutableArray array];
NSMutableArray *vegtables = [NSMutableArray array];
for (NSInteger i = 0; i < array.count; ++i){
if ([array[i] isEqualToString:#"Fruit"]){
++i;
[fruits addObject:array[i]];
}
else if ([array[i] isEqualToString:#"Vegtable"]){
++i;
[vegtables addObject:array[i]];
}
}
I have array which has dictionaries. each dictionary is :
NSDictionary *imageAndIndex=[[NSDictionary alloc] initWithObjectsAndKeys:image,[NSNumber numberWithLong:index], nil];
Where the object is image, and the key is NSNumber key made from index.
I want to sort the array according to the NSNumbers indexes so it will become:
0,1,2,3,4 ..
How can i use NSSortDescriptor ?
The problem (and the debate herein) is complicated by two factors: 1) The OP design choice to sort based on a dictionary key, rather than on a value. #sooper in comments pointed out correctly that the better design would be to add a #"sortBy" key, whose value is the NSNumber to be sorted. 2) The second complication is the question's reference to NSSortDescriptor, which is going to depend upon values for a given key, not the key itself.
I think the right answer is to take the #sooper suggestion to add #"sortBy" key-value pairs, but if you must sort the data as is...
- (void)sortDictionaries {
NSDictionary *d0 = #{ #0: someUIImage0};
NSDictionary *d1 = #{ #1: someUIImage1};
NSDictionary *d2 = #{ #": someUIImage2};
NSArray *unsorted = #[d1, d2, d0];
NSArray *sorted = [unsorted sortedArrayUsingComparator:^(NSDictionary *obj1, NSDictionary *obj2) {
NSNumber *key1 = [self numericKeyIn:obj1];
NSNumber *key2 = [self numericKeyIn:obj2];
return [key1 compare:key2];
}];
NSLog(#"%#", sorted);
}
- (NSNumber *)numericKeyIn:(NSDictionary *)d {
// ps. yuck. what do we want to assume here?
// that it's a dictionary?
// that it has only one key value pair?
// that an NSNumber is always one of the keys?
return [d allKeys][0];
}
Not sure why we had to handle this with so much ill-temperment. It's programming, it's supposed to be fun!
Anyway, here's how you'd do it with a sort key and sort descriptor:
- (void)betterSortDictionaries {
NSDictionary *d0 = #{ #"image":image1, #"sortBy":#0 };
NSDictionary *d1 = #{ #"image":image2, #"sortBy":#1 };
NSDictionary *d2 = #{ #"image":image3, #"sortBy":#2 };
NSArray *unsorted = #[d1, d2, d0];
NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:#"sortBy" ascending:YES];
NSArray *sorted = [unsorted sortedArrayUsingDescriptors:#[descriptor]];
NSLog(#"%#", sorted);
}
i have 2 nsarrays
1 with nsdictionary's another with nsnumbers
NSArray *arr1 = #[#{#"id":#1},#{#"id":#2},#{#"id":#3},#{#"id":#4}];
NSArray *arr2 = #[#3,#1,#4,#2];
and i want to sort my arr1 through their id following the order of arr2
is this possible?
The problem with using sortedArrayUsingComparator: is you start dealing with O(n^2) lookup times. For each sort comparison in the first array, you have to do a lookup in the second array.
Your best bet is to take advantage of a hash table to reduce that to O(n) average complexity.
Your first step is to create a dictionary using id as a key. The result would look something like #{#1: #{#"id":#"1"}, ...}. Then you just have to construct an array by looping through arr3 and grabbing the values.
NSArray *arr1 = #[#{#"id":#1},#{#"id":#2},#{#"id":#3},#{#"id":#4}];
NSArray *arr2 = #[#3,#1,#4,#2];
NSMutableDictionary *map = [NSMutableDictionary dictionary];
for (NSDictionary *item in arr1) {
map[item[#"id"]] = item;
}
NSMutableArray *arr3 = [NSMutableArray array];
for (id key in arr2) {
[arr3 addObject:map[key]];
}
This solution of course assumes parity between the two arrays. If arr2 has an element not in arr1 it will crash when trying to add nil to arr3. If arr1 has a value not in arr2 it will be excluded from arr3. These are risks you will have to address based on your requirements.
Here is how you can do it by using a custom comparator:
NSArray* sorted= [arr1 sortedArrayUsingComparator: ^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
return [arr2 indexOfObject:obj1[#"id"]] - [arr2 indexOfObject:[obj2[#"id"]];
}];
I exploited the fact that NSComparisonResult has +1 to represent an ascending order, -1 for descending and 0 to represent the same order.
- (NSArray*) sortedArray
{
NSArray *arr1 = #[#{#"id":#1},#{#"id":#2},#{#"id":#3},#{#"id":#4}];
NSArray *arr2 = #[#3,#1,#4,#2];
NSMutableArray *mutableArray = [NSMutableArray new];
for (NSNumber *number in arr2)
{
for (NSDictionary* dictionary in arr1)
{
NSNumber *number2 = dictionary[#"id"];
if ([number isEqual:number2])
{
[mutableArray addObject:dictionary];
break;
}
}
}
return mutableArray;
}
Very simple problem, I am on the right track, I have to use predicates but couldn't find the solution.
I have two arrays:
A = [1, 2, 3, 4]
B = [1, 2]
I want to have an aray C = A \ B that is
C = [3, 4]
Use the right tool for the task. What you're describing here is the set operation "difference".
NSMutableSet *first = [NSMutableSet setWithObjects:#1, #2, #3, #4, nil];
NSSet *second = [NSSet setWithObjects:#1, #2, nil];
[first minusSet:second];
If you really really really need to work with arrays, you can convert between arrays and sets too:
NSArray *array = [someSet allObjects];
or
NSSet *set = [NSSet setWithArray:someArray];
You can achieve it with removeObjectsFromArray:
NSArray * arrayA = #[ #1, #2, #3, #4 ];
NSArray * arrayB = #[ #1, #2 ];
NSMutableArray * arrayC = [arrayA mutableCopy];
[arrayC removeObjectsInArray:arrayB];
EDIT
As suggested in the comments and also proposed by H2CO3, if you don't have a valid reason to use NSArray, the most convenient solution is to change data structure and switch to NSSet, which has the support for set difference, using the method -minusSet:.
EDIT 2
As Sven noted in the comments, your objects must respond properly to hash and isEqual: in order to use removeObjectsInArray:. In the above example everything will work just fined, since NSNumber has a default implementation for those methods, but in case you're using a custom class you need to explicitly override them.
Here's another approach:
NSArray * arrayA = #[ #1, #2, #3, #4 ];
NSArray * arrayB = #[ #1, #2 ];
NSIndexSet *indexSet = [arrayA indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
if([arrayB containsObject:obj]){
return NO;
}
else{
return YES;
}
}];
NSArray *arrayC = [arrayA objectsAtIndexes:indexSet];