This question already has answers here:
can anyone tell flow of execution of blocks in objective c? [closed]
(3 answers)
Closed 9 years ago.
I am working with Objective-C blocks, but I'm having troubles understanding the below code execution.
Here is the code :
NSArray *array = #[#"A", #"B", #"C", #"A", #"B", #"Z", #"G", #"are", #"Q"];
NSSet *filterSet = [NSSet setWithObjects: #"A", #"Z", #"Q", nil];
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
test = ^(id obj, NSUInteger idx, BOOL *stop) {
if (idx < 5) {
if ([filterSet containsObject: obj]) {
return YES;
}
}
return NO;
};
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
NSLog(#"indexes: %#", indexes);
Output:
indexes: <NSIndexSet: 0x10236f0>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]
In this method, [array indexesOfObjectsPassingTest:test];, the test block is the parameter I passed.
But in the above block, test = ^(id obj, NSUInteger idx, BOOL *stop) what are the values of the parameters obj, idx and stop it can take? Where are they from?
You have 9 items in your array. So the test block is executed 9 times.
Each time, obj will be the object from the array. And idx will be the index.
First time: obj=#"A" idx=0
Second time: obj=#"B" idx=1
etc.
stop is a value you can write to, if you wanted to exit early. So if on the 5th time through the block, you didn't want to do it anymore. you could do *stop=YES;
Related
I have a NSMutableArray with multiple repeated strings, I am trying to get last string index.
NSMutableArray *arrWithRepeatedStrings=[[NSMutableArray alloc]initWithObjects:#"iOS",#"apple",#"iOS",#"apple",#"apple",#"iOS", nil];
here iOS and apple are the repeated strings in my array. I think it's possible and am on the way to it. Can anyone help me.
You can get the index of last occurrence of string by enumerating in the reverse direction. Use the code below. You can change the matching string to #"iOS" if you want it's index and not #"apple".
NSMutableArray *arrWithRepeatedStrings=[[NSMutableArray alloc]initWithObjects:#"iOS",#"apple",#"iOS",#"apple",#"apple",#"iOS", nil];
NSInteger index = [arrWithRepeatedStrings indexOfObjectWithOptions:NSEnumerationReverse passingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
if([obj isEqualToString: #"apple"])
return YES;
else
return NO;
}];
I understand the question that you want the index of the last object that is more than once in the array. This is quite different from what #Gandalf's solution does, so here's my take:
NSInteger index = [array indexOfObjectWithOptions:NSEnumerationReverse
passingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
BOOL match = [arrWithRepeatedStrings indexOfObject:obj] != idx;
if (match) *stop = YES;
return match;
}];
This question already has answers here:
Sorting two NSArrays together side by side
(4 answers)
Closed 7 years ago.
I'm trying to add fb friends scores table and I'm facing the problem by sorting them. From request, I'm getting two mutable arrays, one with friends name and one with their scores. Now I need to sort the scores in descending order (from highest to lowest). Sorting only scores is easy with this code:
NSSortDescriptor *scoreSorter= [[NSSortDescriptor alloc] initWithKey:#"self" ascending:NO];
[self.friendScoresArray sortUsingDescriptors:[NSArray arrayWithObject:scoreSorter]];
but if I do like this, I'm losing the connection between name and score, so I need to sort the names also now. Here's the example what happens now:
After request:
(Name - Score)
Name One - 110
Name Two - 120
Name Three - 100
After sorting the scores:
Name One - 120
Name Two - 110
Name Three - 100
This is obvious of course, but just a quick example of what I'm getting. Also, I've tried old method from C++ called bubble method. It's worked, but it's slow and sometimes giving ascending order, so that is bad practice in my opinion. So, what's the best way to sort out those to arrays without loosing connect between name and score? Thank you.
Pack each name and score into an object, stick that object into an array, sort that array based on the score member. I think this method should work quite well.
I would do something like this:
NSArray *_names = [NSArray arrayWithObjects:#"Jack", #"Zoe", #"Natalie", nil];
NSArray *_scores = [NSArray arrayWithObjects:#(110), #(120), #(100), nil];
NSMutableArray *_combined = [NSMutableArray array];
#define kName #"kName"
#define kScore #"kScore"
[_names enumerateObjectsUsingBlock:^(NSString * name, NSUInteger idx, BOOL *stop) {
NSNumber *_score = [_scores objectAtIndex:idx];
[_combined addObject:[NSDictionary dictionaryWithObjectsAndKeys:name, kName, _score, kScore, nil]];
}];
[_combined sortWithOptions:NSSortStable usingComparator:^NSComparisonResult(NSDictionary * obj1, NSDictionary * obj2) {
Float64 _score1 = [[obj1 valueForKey:kScore] doubleValue], _score2 = [[obj2 valueForKey:kScore] doubleValue];
if (_score1 < _score2) return NSOrderedDescending;
else return NSOrderedAscending;
}];
the input:
Jack - 110
Zoe - 120
Natalie - 100
the output:
Zoe - 120
Jack - 110
Natalie - 100
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]];
}];
This question already has answers here:
How to implement searching of a string in an array of dictionaries?
(2 answers)
Searching NSArray of NSDictionary objects
(3 answers)
Closed 8 years ago.
I have a NSArray looking like:
[{#"firstName":#"abc", #"lastName":#"ABC"},
...
{#"firstName":#"xyz", #"lastName":#"XYZ"}]
I want to get the dictionary element in which lastName=XYZ, that is, the array element:
{#"firstName":#"xyz", #"lastName":#"XYZ"}
is there an easy way to get it without a lot of loops? Thanks.
NSArray *people = ...;
NSUInteger chosenIndex = [people indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
NSDictionary *person = obj;
return [person[#"lastName"] isEqualToString:#"XYZ"];
}];
if (chosenIndex != NSNotFound) {
NSDictionary *chosenPerson = people[chosenIndex];
NSLog(#"I chose %#", chosenPerson);
}
This question already has answers here:
Filter NSArray of custom objects
(3 answers)
Closed 9 years ago.
I have NSMutableArray which contains a list of people , now I need to get a list of all people where gender = male, how can I do that? should I get into NSPredicates to do that?
Copy this NSArray category to to somewhere in your code
#implementation NSArray (My)
-(NSArray*)arrayWithPredicate:(BOOL(^)(id obj))predicate {
NSMutableArray* objs = [NSMutableArray array];
[self enumerateObjectsUsingBlock:^(id o, NSUInteger idx, BOOL *stop) {
if (predicate(o)) {
[objs addObject:o];
}
}];
return objs;
}
#end
Then where you need to get the male ones:
NSArray* males = [people arrayWithPredicate:^BOOL(id obj) {
// Gender check
}];
The advantage over NSPredicate is that you don't have to use a literal string to specify the criteria (quite a mess if the criteria is complex).
yes you can use like this,
NSArray *filtered = [data filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"self.gender == %#", #"male"]];
NSLog(#"%#",filtered);
I have NSMutableArray with objects like this : "0,1,0,1,1,1,0,0"
And i need to get indexes of all objects with value "1"
I'm trying to get it with following code:
for (NSString *substr in activeItems){
if ([substr isEqualToString:#"1"]){
NSLog(#"%u",[activeItems indexOfObject:substr]);
}
}
But as it says in documentation method indexOfObject: " returns - The lowest index whose corresponding array value is equal to anObject."
Question: How i can get all indexes of array with value of "1" ?
You can use this method of NSArray:
- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
(documentation here.)
NSIndexSet *set = [array indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [obj isEqualToString:#"1"];
}];
And this is how you can get the indexes as the elements of an array (represented by NSNumber objects):
NSIndexSet *set = // obtain the index set as above
NSUInteger size = set.count;
NSUInteger *buf = malloc(sizeof(*buf) * size);
[set getIndexes:buf maxCount:size inIndexRange:NULL];
NSMutableArray *array = [NSMutableArray array];
NSUInteger i;
for (i = 0; i < size; i++) {
[array addObject:[NSNumber numberWithUnsignedInteger:buf[i]]];
}
free(buf);
and then array will contain all the indexes of the matching objects wrapped in NSNumbers.
You can use [NSArray indexesOfObjectsPassingTest:] (reference):
NSIndexSet *indexes = [activeItems indexesOfObjectsPassingTest:^BOOL (id obj, NSUInteger idx, BOOL *stop) {
return [obj isEqualToString:#"1"];
}];
Once you have the indexes, you can get the subset of the original array, containing just the objects you are interested in, using [NSArray objectsAtIndexes:] (reference):
NSArray *subset = [activeItems objectsAtIndexes:indexes];
Simply use the indexesOfObjectsPassingTest: method of NSArray, providing a block as argument to check your objects.
It will return a NSIndexSet.
- (NSIndexSet *)indexesOfObjectsPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
And then to access indexes from the NSIndexSet,
[indexset enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
//idx is what you want!
}];