Get indexes of same object in NSMutableArray - ios

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!
}];

Related

Find index of value which is stored into NSDictionary and NSDictionary stored into NSMutableArray

I have NSMutableArray which stores NSDictionary. Consider following array which contain NSDictionary.
<__NSArrayM 0x7f9614847e60>(
{
"PARAMETER_KEY" = 1;
"PARAMETER_VALUE" = ALL;
},
{
"PARAMETER_KEY" = 2;
"PARAMETER_VALUE" = ABC;
},
{
"PARAMETER_KEY" = 3;
"PARAMETER_VALUE" = DEF;
},
{
"PARAMETER_KEY" = 4;
"PARAMETER_VALUE" = GHI;
},
{
"PARAMETER_KEY" = 5;
"PARAMETER_VALUE" = JKL;
}
)
I can find index of specific NSDictionary using following code.
int tag = (int)[listArray indexOfObject:dictionary];
But If I have PARAMETER_VALUE = GHI and using this value I want to find that dictionary index into array. I don't want to use for loop. Can I get index without for loop?
You can use indexOfObjectPassingTest method of NSArray:
[listArray indexOfObjectPassingTest:^BOOL(NSDictionary* _Nonnull dic, NSUInteger idx, BOOL * _Nonnull stop) {
return [dic[#"PARAMETER_VALUE"] isEqualToString:#"GHI"];
}];
Also, please consider using indexesOfObjectsPassingTest if you can have multiple dictionaries with the same PARAMETER_VALUE
You can add a category on NSArray like this (this does a type safety check as well; only array of dictionaries are processed):
- (NSInteger)indexOfDictionaryWithKey:(NSString *)iKey andValue:(id)iValue {
NSUInteger index = [self indexOfObjectPassingTest:^BOOL(NSDictionary *dict, NSUInteger idx, BOOL *stop) {
if (![dict isKindOfClass:[NSDictionary class]]) {
*stop = YES;
return false;
}
return [dict[iKey] isEqual:iValue];
}];
return index;
}
And then simply call indexOfDictionaryWithKey:andValue: directly on your array object to get the index.
Just in case if you want to get the dictionary object out of that array, add one more category in NSArray:
- (NSDictionary *)dictionaryWithKey:(NSString *)iKey andValue:(id)iValue {
NSUInteger index = [self indexOfDictionaryWithKey:iKey andValue:iValue];
return (index == NSNotFound) ? nil : self[index];
}
You can use NSPredicate for this purpose:
// Creating predicate
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"SELF.PARAMETER_VALUE MATCHES %#",#"GHI"];
// Filtering array
NSArray *filteredArr = [arr filteredArrayUsingPredicate:predicate];
// If filtered array count is greater than zero (that means specified object is available in the array), checking the index of object
// There can be multiple objects available in the filtered array based on the value it holds (In this sample code, only checking the index of first object
if ([filteredArr count])
{
NSLog(#"Index %d",[arr indexOfObject:filteredArr[0]]);
}
Well, one has to enumerate in a way. Taking your requirement literally (no for loop), you can use fast enumeration. However, the task can be run concurrently, because you only need read access:
__block NSUInteger index;
[array enumerateObjectsWithOptions: NSEnumerationConcurrent
usingBlock:
^(NSDictionary *obj, NSUInteger idx, BOOL *stop)
{
if( [obj valueForKey:#"PARAMETER_VALUE" isEqualToString:#"GHI" )
{
index = idx;
*stop=YES;
}
}

Get index of last repeated string in NSMutableArray

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

Find index of all duplicate elements in NSArray

It's hard to explain why I need index of duplicate elements in array. When I tried to fetch the index of element in traditional way it shows only one index, but I need to fetch the all index of duplicate values
for ex:
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
int index = [array indexOfObject:element];
NSLog(#"index %d",index);
here if I try to fetch index of " one " it shows index is 0 but I need to get further indexes of one
You can fetch the index of duplicates like this:
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop)
{
if ([obj isEqualToString:#"one"])
{
NSLog(#"index %d",idx);
}
}];
int i,count=0;
for (i = 0; i < [array count]; i++) {
if element == [array objectAtIndex:i] {
indices[count++] = i;
}
}
Declare an empty array indices, and indices will contain all the indices of the given element.
NSString *element = #"one";
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
NSIndexSet *matchingIndexes = [array indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [obj isEqual:element];
}];
[matchingIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"%ld", (long)idx);
}];
Ultimately I don't think the NSArray methods are going to help you here, so you're going to have to write some pretty basic code. There is probably a cleaner answer, but here is a fairly simply solution to the problem.
This just goes through the array, and creates an NSDictionary for each unique number. It assumes the array is sorted as your example was, so simply checks the prior index's value against the current index to see if they have changed. When they change, it knows it's done with that value and saves the dictionary to an array.
NSArray *array=#[#"one",#"one",#"one",#"two",#"two",#"four",#"four",#"four"];
NSString *priorString = array[0];
NSMutableDictionary *duplicatesByKey = [[NSMutableDictionary alloc] init];
NSMutableArray *indexesOfDuplicates = [[NSMutableArray alloc] init];
int index = 0;
for (NSString *string in array) {
if ([priorString isEqualToString:string]) {
[indexesOfDuplicates addObject:[NSNumber numberWithInt:index]];
} else {
[duplicatesByKey setObject:indexesOfDuplicates forKey:priorString];
indexesOfDuplicates = [[NSMutableArray alloc] init];
[indexesOfDuplicates addObject:[NSNumber numberWithInt:index]];
}
priorString = string;
index ++;
}
[duplicatesByKey setObject:indexesOfDuplicates forKey:priorString];
I hope that helps.
Use
NSCountedSet * countedSet = [NSCountedSet setWithArray: array];
and
NSSet * uncountedSet = [NSSet setWithArray: array];
-- to create a counted set from your array, and a conventional NSSet.
Then:
[countedSet minusSet: uncountedSet];
countedSet will now contain only elements for the duplicates (if any), and the countForObject: method will return the number of duplicates (in excess of 1) for that element.

Best way for getting the indexes of matched objects in NSArray in iOS?

I have the following two arrays.
NSArray *array1=[[NSArray alloc]initWithObjects:#"ABC",#"DEF", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"ABC",#"123",#"DEF",#"DEF", nil];
Now i have to search each array1's object and in array2 and need to get the matched indexes.
And my application contains more than one thousand objects in array2.
Please suggest the best possible way other than putting second for loop in first for loop
for (int i=0; i<array1.count; i++)
{
//Need to search the [array1 objectAtIndex:i] string in array2 and need to get the matched indexes into an array in best optimised way here.
NSMutableArray *matchedIndexesArray=[[NSMutableArray alloc]init];
NSString *stringToSearch=[array1 objectAtIndex:i];
//here i can put another array like below to get the matched indexes..but is there any optimized way other than this for loop here? or is there any simple inbuilt method to get the matched objects into an array here.
for (int j=0; j<array2.count; j++)
{
if ([stringToSearch isEqualToString:[array2 objectAtIndex:j]])
{
[matchedIndexesArray addObject:[NSString stringWithFormat:#"%d",j]];
}
}
NSLog(#"matchedIndexesArray-->%#<--",matchedIndexesArray);
//I will use this matchedIndexesArray here further processing...
//
//
//
//Large Code Here
//
//
//
}
According to the NSSet documentation, membership testing is faster for sets than for arrays.
Therefore it makes sense to convert array1 to a set first:
NSSet *set1 = [NSSet setWithArray:array1];
and then test each object of array2 for membership in the set. This can be conveniently
done as
NSIndexSet *matchingIndexes = [array2 indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [set1 containsObject:obj];
}];
Show all matching indexes:
[matchingIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"%ld", (long)idx);
}];
// Output: 0, 2, 3
UPDATE: (after question edit) No, there is no method to fill an NSArray with the indices of matching objects. But there is a method to fill an NSIndexSet. NSIndexSet is a special collection to store indices
into some other data structure, such as an array. Then your code would look like
for (NSString *stringToSearch in array1) {
NSIndexSet *matchingIndexes = [array2 indexesOfObjectsPassingTest:^BOOL(NSString *obj, NSUInteger idx, BOOL *stop) {
return [stringToSearch isEqualToString:obj];
}];
NSLog(#"matchingIndexes: %#", matchingIndexes);
// Work with matchingIndex, for example enumerate all indices:
[matchingIndexes enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
NSLog(#"%ld", (long)idx);
}];
}
But I do not know if it makes much difference in performance.
NSArray *a = #[#"123", #"456", #"ABC", #"DEF"];
NSArray *b = #[#"123", #"ABC", #"---"];
NSIndexSet *indexes = [a indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop)
{
return [b containsObject:obj]
}];
NSLog(#"%#", indexes);
NSArray *array1=[[NSArray alloc]initWithObjects:#"ABC",#"DEF", nil];
NSArray *array2=[[NSArray alloc]initWithObjects:#"ABC",#"123",#"DEF",#"DEF", nil];
for (int i=0; i<array1.count; i++){
for (int j=0; j<array2.count; j++) {
if ([[array1 objectAtIndex:i] isEqualToString: [array2 objectAtIndex:j]]) {
NSLog(#"Matched Indexes %d %#", i, [array1 objectAtIndex:i] );
}
}
}

How to count duplicates values in NSArray?

Value of my NSArray includes the duplicates.
I find the duplicates but now how can I find the no. they repeat?
You can use NSCountedSet for this. Add all your objects to a counted set, then use the countForObject: method to find out how often each object appears.
Example:
NSArray *names = [NSArray arrayWithObjects:#"John", #"Jane", #"John", nil];
NSCountedSet *set = [[NSCountedSet alloc] initWithArray:names];
for (id item in set) {
NSLog(#"Name=%#, Count=%lu", item, (unsigned long)[set countForObject:item]);
}
You can try something like this
__block NSInteger elementCount = 0;
NSArray *array;
[<#NSArray yourArray#> indexesOfObjectsPassingTest:^(id obj, NSUInteger idx, BOOL *stop){
if (obj == <#yourObject#>) {
elementCount++;
return YES;
}
return NO;
}];
Let me know if that works for you

Resources