match NSString against NSString field of an array - objective-c

I have an NSMutableArray called myObjectArray which contains and array of NSObjects called myObject. myObject has two fields (elements?) which are NSString's. like this:
#interface myObject : NSObject {
NSString * string1;
NSString * string2;
}
I have an NSMutableArray which contains about 50 of these objects, all with different string1's and string2's. then I have and independent NSString variable, called otherString;
Is there a fast way to access the myObject from myObjectArray whose string1 matches otherString?
i should say, this is what i have, but i wonder if there is a faster way:
-(void) matchString: {
NSString * testString = otherString;
for(int i=0; i<[myObjectArray count];i++){
myObject * tempobject = [myObjectArray objectAtIndex:i];
NSString * tempString = tempobject.string1;
if ([testString isEqualToString:tempString]) {
// do whatever
}
}
}

There are a few ways you can do this,
Using Predicates
NSPredicate * filterPredicate = [NSPredicate predicateWithFormat:#"string1 MATCHES[cd] %#", otherString];
NSArray * filteredArray = [myObjectArray filteredArrayUsingPredicate:filterPredicate];
Now filteredArray has all the myObject instances that have their string1 matching otherString.
Using indexOfObjectPassingTest:
NSUInteger index = [myObjectArray indexOfObjectPassingTest:^(BOOL)(id obj, NSUInteger idx, BOOL *stop){
myObject anObject = obj;
return [anObject.string1 isEqualToString:otherString];
}
If there is an object that satisfies the condition, index will point you to its index. Otherwise it will have the value NSNotFound.
You can also look at indexesOfObjectsPassingTest: if you want all the objects satisfying the condition.

Related

Call class method and return a dictionary on objective c category

I have made a category in my x-code project like below:
+ (NSDictionary *)anagramMap {
static NSDictionary *anagramMap;
if (anagramMap != nil)
return anagramMap;
// this file is present on Mac OS and other unix variants
NSString *allWords = [NSString stringWithContentsOfFile:#"/usr/share/dict/words"
encoding:NSUTF8StringEncoding
error:NULL];
NSMutableDictionary *map = [NSMutableDictionary dictionary];
#autoreleasepool {
[allWords enumerateLinesUsingBlock:^(NSString *word, BOOL *stop) {
NSString *key = [word anagramKey];
if (key == nil)
return;
NSMutableArray *keyWords = [map objectForKey:key];
if (keyWords == nil) {
keyWords = [NSMutableArray array];
[map setObject:keyWords forKey:key];
}
[keyWords addObject:word];
}];
}
anagramMap = map;
return anagramMap;}
- (NSString *)anagramKey {
NSString *lowercaseWord = [self lowercaseString];
// make sure to take the length *after* lowercase. it might change!
NSUInteger length = [lowercaseWord length];
unichar sortedWord[length];
[lowercaseWord getCharacters:sortedWord range:(NSRange){0, length}];
qsort_b(sortedWord, length, sizeof(unichar), ^int(const void *a, const void *b) {
unichar c1 = *(const unichar *)a;
unichar c2 = *(const unichar *)b;
if (c1 > c2)
return -1;
if (c1 < c2)
return 1;
return 0;
});
return [NSString stringWithCharacters:sortedWord length:length];}
Basically, this code loops through the Mac OSx dictionary and turns it into an NSDictionary where the key is the alphabetically sorted word, and the object is an array of all the anagrams of that word.
What I was wondering, is how can I call this method, such as in the viewDidLoad part of an implementation file which would assign an NSDictionary (or mutable) this created dictionary of the sorted key and object array? Basically in pseudo code i do something like:
NSMutatableArray *englishDictionary = [[NSMutableArray alloc] init];
englishDictionary = [NSMutableArray anagramMapScrabble];
//Should mean now englishDictionary has turned into the NSDictionary where the key = sorted word and object is an array of English anagrams of that sorted word
I think I'd have to put some extra code in the methods but I'm not sure. Any suggestions would be much appreciated!
A category is a modification of an existing class. It works exactly the same as if the methods of the category were declared in that class - because they are. So it works like every other method. If you make a category on, say, NSObject declared like this:
+ (NSDictionary *)anagramMap;
Then that is a class method of NSObject and you call it by saying:
NSDictionary* d = [NSObject anagramMap];
If you make a category on NSObject declared like this:
- (NSDictionary *)anagramMap;
Then that is an method of NSObject and you call it by saying:
NSObject* o = [NSObject new];
NSDictionary* d = [o anagramMap];

How to add a number of objects skipping nil objects to NSMutableArray?

I need a method that would add a few objects (2-10) to my array, skipping these that are nils:
NSMutableArray *arr = [[NSMutableArray alloc] init];
[arr addObjectsSkipNils:obj1, obj2, obj3];
How I can write this method in an elegant way?
This category method would work:
#interface NSMutableArray (MyAdditions)
- (void)addObjectsSkipNilsWithCount:(NSUInteger)count objects:(id)obj, ...;
#end
#implementation NSMutableArray (MyAdditions)
- (void)addObjectsSkipNilsWithCount:(NSUInteger)count objects:(id)obj, ...
{
va_list ap;
va_start(ap, obj);
// First object:
if (obj != nil)
[self addObject:obj];
// Remaining objects:
for (NSUInteger i = 1; i < count; i++) {
id myobj = va_arg(ap, id);
if (myobj != nil)
[self addObject:myobj];
}
va_end(ap);
}
#end
Example:
NSMutableArray *a = [NSMutableArray array];
[a addObjectsSkipNilsWithCount:3 objects:#"foo", nil, #"bar"];
NSLog(#"%#", a);
// Output: ( foo, bar )
You have to specify the number of objects explicitly, because nil cannot be used as terminator for the variable argument list. (And bad things can happen if the count is greater than the actual number of objects supplied !)
You can use:
[yourMainArray removeObjectIdenticalTo:[NSNull null]];
Now if you want to copy this to arr you can do quite easily.

Is there a way to specify a specific object index in a valueForKeyPath statement?

In calling NSDictionary valueForKeyPath if one level of the path is an array can you specify a specific element in the array?
For example:
[myDict valueForKeypath:#"customer.contactInfo.phoneNumbers[4].countryCode];
where .phoneNumbers is an NSArray. Or do I have to:
NSArray *numbers=[myDict valueForKeypath:#"customer.contactInfo.phoneNumbers];
NSString *countryCode=[[numbers objectAtIndex:4] objectForKey:#"countryCode"];
It would be really nice and much cleaner if this could be done in one statement.
You could do this:
NSString *myString = [[[myDict valueForKeypath:#"customer.contactInfo.phoneNumbers"] objectAtIndex:4] objectForKey:#"countryCode"];
Here's a category I wrote for NSObject that can handle array indexes so you can access your nested object like this: "customer.contactInfo.phoneNumbers[4].countryCode"
#interface NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath;
#end
#import "NSObject+ValueForKeyPathWithIndexes.h"
#implementation NSObject (ValueForKeyPathWithIndexes)
-(id)valueForKeyPathWithIndexes:(NSString*)fullPath
{
//quickly use standard valueForKeyPath if no arrays are found
if ([fullPath rangeOfString:#"["].location == NSNotFound)
return [self valueForKeyPath:fullPath];
NSArray* parts = [fullPath componentsSeparatedByString:#"."];
id currentObj = self;
for (NSString* part in parts)
{
NSRange range = [part rangeOfString:#"["];
if (range.location == NSNotFound)
{
currentObj = [currentObj valueForKey:part];
}
else
{
NSString* arrayKey = [part substringToIndex:range.location];
int index = [[[part substringToIndex:part.length-1] substringFromIndex:range1.location+1] intValue];
currentObj = [[currentObj valueForKey:arrayKey] objectAtIndex:index];
}
}
return currentObj;
}
#end
Use it like so
NSString* countryCode = [myDict valueForKeyPathWithIndexes:#"customer.contactInfo.phoneNumbers[4].countryCode"];
There's no error checking, so it's prone to breaking but you get the idea. I cross posted this answer to a similar (linked) question.

Would like NSArray valueForKey to return the array indices

I can create an NSArray that contains all the hash values of the objects in myArray like this:
NSArray *a = [myArray valueForKey:#"hash"];
What key do I pass to valueForKey: to get an array containing myArray's indices?
Say myArray has n items. I'd like to do something like this:
NSArray *a = [myArray valueForKey:#"index"];
NSArray * arrayWithNumbersInRange( NSRange range )
{
NSMutableArray * arr = [NSMutableArray array];
NSUInteger i;
for( i = range.location; i <= range.location + range.length; i++ ){
[arr addObject:[NSNumber numberWithUnsignedInteger:i];
}
return arr;
}
NSArray * indexArray = arrayWithNumbersInRange((NSRange){0, [myArray length]-1});
You can query an NSArray for the index of an object with indexOfObject:
NSArray *a = [myArray valueForKey:#"hash"];
NSInteger index = [myArray indexOfObject:a];
Create a superclass of NSArray which returns the index:
//
// CapArrayOfIndex.h
// Created by carmin politano on 7/26/12.
// no rights reserved
//
#interface CapArrayOfIndex : NSArray {
/*! Simulated constant array containing an array of NSNumber representing the index. */
NSUInteger iCount;
//*! NSNotFound causes bybass of index bounds testing. */
}
#pragma mark create
+ (CapArrayOfIndex*) withCount: (NSUInteger) aCount;
#end
and
//
// CapArrayOfIndex.mm
// Created by carmin on 7/26/12.
// no rights reserved
//
#import "CapArrayOfIndex.h"
#implementation CapArrayOfIndex
#pragma mark NSCopying
- (id) copyWithZone: (NSZone*) aZone {
/*! New allocation required because -count is a mutable property. */
return [CapArrayOfIndex withCount: self.count];
}
#pragma mark create
+ (CapArrayOfIndex*) withCount: (NSUInteger) aCount {
CapArrayOfIndex* zArray = self.alloc;
zArray->iCount = aCount;
return zArray;
}
#pragma mark NSArray
- (NSUInteger) count {
return iCount;
}
- (void) setCount: (NSUInteger) aCount {
iCount = aCount;
}
- (id) objectAtIndex: (NSUInteger) aIndex {
/*! My code performs a bounds test using unusual macros: return [ViaUInteger RaiseIfObjectAtIndex(nil, self, aIndex, nil)]; */
return [NSNumber numberWithInteger: aIndex];
}
#end

How to get indexes from NSIndexset into an NSArray in cocoa?

I'm getting the select items from a table view with:
NSIndexSet *selectedItems = [aTableView selectedRowIndexes];
what's the best way to get the indexes in a NSArray object?
Enumerate the set, make NSNumbers out of the indexes, add the NSNumbers to an array.
That's how you'd do it. I'm not sure I see the point in transforming a set of indexes into a less efficient representation, though.
To enumerate a set, you have two options. If you're targeting OS X 10.6 or iOS 4, you can use enumerateIndexesUsingBlock:. If you're targeting earlier versions, you'll have to get the firstIndex and then keep asking for indexGreaterThanIndex: on the previous result until you get NSNotFound.
NSIndexSet *selectedItems = [aTableView selectedRowIndexes];
NSMutableArray *selectedItemsArray=[NSMutableArray array];
[selectedItems enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
[selectedItemsArray addObject:[NSNumber numberWithInteger:idx]];
}];
With swift you can do the following
extension NSIndexSet {
func toArray() -> [Int] {
var indexes:[Int] = [];
self.enumerateIndexesUsingBlock { (index:Int, _) in
indexes.append(index);
}
return indexes;
}
}
then you can do
selectedItems.toArray()
Here is the sample code:
NSIndexSet *filteredObjects = [items indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {do testing here}];
NSArray *theObjects = [theItems objectsAtIndexes:filteredObjects]
Availability
Available in iOS 2.0 and later.
I did it by creating a category on NSIndexSet. This kept it small and efficient, requiring very little code on my part.
My interface (NSIndexSet_Arrays.h):
/**
* Provides a category of NSIndexSet that allows the conversion to and from an NSDictionary
* object.
*/
#interface NSIndexSet (Arrays)
/**
* Returns an NSArray containing the contents of the NSIndexSet in a format that can be persisted.
*/
- (NSArray*) arrayRepresentation;
/**
* Returns an array of NSNumber objects representing each index in the set.
*/
- (NSArray<NSNumber*>*) arrayOfNumbersRepresentation;
/**
* Initialises self with the indexes found wtihin the specified array that has previously been
* created by the method #see arrayRepresentation.
*/
+ (NSIndexSet*) indexSetWithArrayRepresentation:(NSArray*)array;
#end
and the implementation (NSIndexSet_Arrays.m):
#import "NSIndexSet_Arrays.h"
#implementation NSIndexSet (Arrays)
/**
* Returns an NSArray containing the contents of the NSIndexSet in a format that can be persisted.
*/
- (NSArray*) arrayRepresentation {
NSMutableArray *result = [NSMutableArray array];
[self enumerateRangesUsingBlock:^(NSRange range, BOOL *stop) {
[result addObject:NSStringFromRange(range)];
}];
return [NSArray arrayWithArray:result];
}
/**
* Returns an array of NSNumber objects representing each index in the set.
*/
- (NSArray<NSNumber*>*) arrayOfNumbersRepresentation {
NSMutableArray<NSNumber*> *result = [NSMutableArray array];
[self enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL * _Nonnull stop) {
[result addObject:[NSNumber numberWithInteger:idx]];
}];
return [NSArray arrayWithArray:result];
}
/**
* Initialises self with the indexes found wtihin the specified array that has previously been
* created by the method #see arrayRepresentation.
*/
+ (NSIndexSet*) indexSetWithArrayRepresentation:(NSArray*)array {
NSMutableIndexSet *result = [NSMutableIndexSet indexSet];
for (NSString *range in array) {
[result addIndexesInRange:NSRangeFromString(range)];
}
return result;
}
#end