I can use [NSArray indexOfObject: NSString] to get an index of my search for 1 item. But what can I use or do to get an array of returned indices from my search?
thanks
To get multiple indices, you can use indexesOfObjectsPassingTest::
// a single element to search for
id target;
// multiple elements to search for
NSArray *targets;
...
// every index of the repeating element 'target'
NSIndexSet *targetIndices = [array indexesOfObjectsPassingTest:^ BOOL (id obj, NSUInteger idx, BOOL *stop) {
return [obj isEqual:target];
}];
// every index of every element of 'targets'
NSIndexSet *targetsIndices = [array indexesOfObjectsPassingTest:^ BOOL (id obj, NSUInteger idx, BOOL *stop) {
return [targets containsObject:obj];
}];
Support for blocks were added in iOS 4. If you need to support earlier versions of iOS, indexesOfObjectsPassingTest: isn't an option. Instead, you can use indexOfObject:inRange: to roll your own method:
#interface NSArray (indexesOfObject)
-(NSIndexSet *)indexesOfObject:(id)target;
#end
#implementation NSArray (indexesOfObject)
-(NSIndexSet *)indexesOfObject:(id)target {
NSRange range = NSMakeRange(0, [self count]);
NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init];
NSUInteger idx;
while (range.length && NSNotFound != (idx = [self indexOfObject:target inRange:range])) {
[indexes addIndex: idx];
range.length -= idx + 1 - range.location;
range.location = idx + 1;
}
return [indexes autorelease];
}
#end
If you don't have access to indexOfObjectsPassingTest, as #outis recommends, you could use indexOfObject:inRange: and loop over the results, updating the range to start after the last result finished, and updating the results into your own NSIndexSet, or NSMutableArray, etc.
Related
I am using a tableview controller with the searchbar. I want to get all index positions of the array elements which are related to a search result of any string from a table.
For example: If I have an array containing the following: #"sau",#"jain",#"abc",#"sau",#"zyx" and I search for 'sau' then I want it to output index 0 and 3.
How might I achieve this?
Try following code:
NSArray *array = #[ #"sau", #"jain", #"abc", #"sau", #"zyx" ];
NSString *searchString = #"sau";
NSIndexSet *result = [array indexesOfObjectsPassingTest:^BOOL(NSString *string, NSUInteger idx, BOOL *stop) {
NSRange searchStringRange = [string rangeOfString:searchString options:NSCaseInsensitiveSearch];
return searchStringRange.length > 0;
}];
NSLog(#"Result indexes: %#", result);
Console output is Result indexes: <NSIndexSet: 0x8a80c50>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]
Tune code within the block to match you search logic
Edit
Or to process objects on one by one basis
NSArray *array = #[ #"sau", #"jain", #"abc", #"sau", #"zyx" ];
NSString *searchString = #"sau";
[array enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
BOOL searchCondition = [obj isEqualToString:searchString];
if (!searchCondition) return;
// You logic to process objects passing the search condition
}];
I need to search the index of a string from NSMutableArray. I have implemented the code & which works perfect, but I need to increase the searching speed than this.
I have used the following code:
NSIndexSet *indexes = [mArrayTableData indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop){
NSString *s = (NSString*)obj;
NSRange range = [s rangeOfString: txtField.text options:NSCaseInsensitiveSearch];
if(range.location == 0)//
return range.location != NSNotFound;
return NO;
}];
NSLog(#"indexes.firstIndex =%d",indexes.firstIndex);
There is a method indexOfObject
NSString *yourString=#"Your string";
NSMutableArray *arrayOfStrings = [NSMutableArray arrayWithObjects: #"Another strings", #"Your string", #"My String", nil];
NSInteger index=[arrayOfStrings indexOfObject:yourString];
if(NSNotFound == index) {
NSLog(#"Not Found");
}
If you only want one index (or just the first one if there are multiples), you can use the singular version of the method you posted. You also don't need the if clause:
NSInteger index = [mArrayTableData indexOfObjectPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop){
return [obj.lowercaseString isEqualToString:txtField.text.lowercaseString];
}];
If you want to find strings that start with the search string, just replace isEqualToString: with hasPrefix:. With a large search set, this appears to be about twice as fast as the method you posted.
NSMutableArray*array = [[NSMutableArray alloc]init];
NSArray*Somearray = [NSArray arrayWithObjects:1st Object,2ndObject,3rd Object,4th object,5th Object,nil];
In the above array 1st Object,2ndObject,3rd Object,4th object,5th Object having val,content,conclusion in each index.
for(int i=0;i<[Somearray count];i++)
{
______________
Here the code is there to give each index ,that is having val,content,conclusion ..
After that val,content,conclusion in each index will be add to Dict..
____________
NSDictionary *Dict = [NSDictionary dictionaryWithObjectsAndKeys:val,#"val",content,#"content",conclusion,#"conclusion",nil];
//Each time adding dictionary into array;
[array addObject:Dict];
}
The above Dictionary is in for loop and the keyvalue pairs will be add 5 times(Somearray Count).Now array is having in
array = [{val="1.1 this is first one",content="This is the content of 0th index",conclusion="this is the conclusion of 0th index"},{val="1.2 this is first one",content="This is the content of 1st index",conclusion="this is the conclusion of 1st index"},____,____,______,{val="1.5 this is first one",content="This is the content of 4th index",conclusion="this is the conclusion of 4th index"},nil];
Now i am having NSString*string = #"1.5";
Now i need the index where val is having 1.5 in it.How to send the str in to array to find the the index.
Can anyone share the code please.
Thanks in advance.
Use method indexOfObject
int inx= [array indexOfObject:#"1.5"];
For Find index particular key value.
int inx;
for (int i=0; i<[array count]; i++) {
if ([[[array objectAtIndex:i] allKeys] containsObject:#"val"]) {
inx=i;
break;
}
}
The method you are looking for is -[NSArray indexOfObjectPassingTest:]. You would use it like this:
NSUInteger i = [array indexOfObjectPassingTest:^(id obj, NSUInteger idx, BOOL *stop) {
return [[id objectForKey:#"val"] rangeOfString:#"1.5"].location != NSNotFound;
}];
If you just want to check that val starts with "1.5" you would use hasPrefix: instead.
Try this -
NSArray *valArray = [array valueForKey:#"val"];
int index = [valArray indexOfObject:#"1.5"];
Appended answer given by Mandeep, to show you the magic of key value coding ;)
NSUInteger idx = UINT_MAX;
NSCharacterSet* spaceSet = [NSCharacterSet whitespaceCharacterSet];
for(int i=0,i_l=[Yourarray count];i<i_l;i++) {
NSString* s_prime = [[Yourarray objectAtIndex:i] valueForKey:#"val"];
if ([s_prime length] < 4) {
continue;
}
NSString *subString = [[s_prime substringToIndex:4] stringByTrimmingCharactersInSet:spaceSet];
// NSLog(#"index %#",s);
if ([subString isEqualToString:secretNumber]){
idx = i;
break;
}
}
if (idx != UINT_MAX) {
// NSLog(#"Found at index: %d",idx);
} else {
// NSLog(#"Not found");
}
I want to take the values from NSMutableArray but want to read from last index to 1st index
thank you
for (id someObject in [someArray reverseObjectEnumerator])
{
//do your thing
}
2 other options:
Simple for-loop (surely not recommended):
for (int i = [array count]-1; i >= 0; ++i)
id value = [array objectAtIndex: i];
Block-based enumeration:
[array enumerateObjectsWithOptions: NSEnumerationReverse
usingBlock: ^(id obj, NSUInteger idx, BOOL *stop){
//do something
}];
Mark's answer is useful, but this form may be useful when you want to mutate the array:
while ([arr count]) {
id obj = [arr lastObject];
// use obj
[arr removeLastObject];
}
Suppose I have an array having elements "am","john","rosa","freedom". I want to compare these elements and result would be the word and the size of the longest word. I am using objective C.
There isn't a "built-in" way of doing this, however you can use NSArray's sortedArrayUsingSelector: and create a category on NSString to provide a lengthCompare: method.
// NSString+LengthCompare.h
#import NSString.h
#interface NSString (LengthComparison)
- (NSComparisonResult)lengthCompare:(NSString *)aString;
#end
// NSString+LengthCompare.m
#import NSString+LengthCompare.h
#implememtation NSString (LengthComparison)
- (NSComparisonResult)lengthCompare:(NSString *)aString
{
if ([self length] < [aString length]) {
return NSOrderedAscending;
} else if ([self length] > [aString length]) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}
#end
Now you can sort an of strings in ascending order using lengthCompare:
NSArray *array = [NSArray arrayWithObjects: #"am", #"john", #"rosa", #"freedom", nil];
NSArray *arraySortedByStringLength = [array sortedArrayUsingSelector:#selector(lengthCompare:)];
NString *shortestWord = [[arraySortedByStringLength objectAtIndex:0] retain];
NSLog(#"shortest word, %# has length %d", shortestWord, [shortestWord length];
[shortestWord release];
NString *longestWord = [[arraySortedByStringLength lastObject] retain];
NSLog(#"Longest word, %# has length %d", longestWord, [longestWord length];
[longestWord release];
Sounds like a classical logic exercise or is it something I miss in your question ?
int longestWordIndex = 0;
NSUInteger longestWordSize = 0;
for (int i=0 ; i<[nameArray count] ; i++) {
NSString* element = (NSString*)[nameArray objectAtindex:i];
if([element lenght] > longestWordSize) {
longestWordSize = [element lenght];
longestWordIndex = i;
}
}
NSLog("Longest word is %# with size of :%d", [nameArray objectAtIndex:longestWordIndex], longestWordSize);
I'll add one more approach to the two above -- use a block to do the body of your iteration.
__block NSUInteger longestWordSize = -1; // Make sure at least one object will be longer.
__block NSUInteger longestWordIndex;
[nameArray enumerateObjectsUsingBlock:^(id currentWord, NSUInteger index, BOOL *stop) {
if ([currentWord length] > longestWordSize) {
longestWordSize = [currentWord length];
longestWordIndex = index;
}
}];
NSLog("Longest word is %# with size of :%d", [nameArray objectAtIndex:longestWordIndex], longestWordSize);
Edit: The max and index have to be of storage type __block so they can be changed from inside the block.