Case Insensitive Search in NSMutableDictionary
Asked Answered
D

4

6

HI, I have a NSMutableDicitionary contains both lowercase and uppercase keys. So currently i don't know how to find the key in the dictionary irrespective key using objective c.

Disruptive answered 26/5, 2011 at 7:14 Comment(0)
S
6

Categories to the rescue. Ok, so it's an old post...

@interface NSDictionary (caseINsensitive)
-(id) objectForCaseInsensitiveKey:(id)aKey;
@end


@interface NSMutableDictionary (caseINsensitive)
-(void) setObject:(id) obj forCaseInsensitiveKey:(id)aKey ;
@end


@implementation NSDictionary (caseINsensitive)

-(id) objectForCaseInsensitiveKey:(id)aKey {
    for (NSString *key in self.allKeys) {
        if ([key compare:aKey options:NSCaseInsensitiveSearch] == NSOrderedSame) {
            return [self objectForKey:key];
        }
    }
    return  nil;
}
@end


@implementation NSMutableDictionary (caseINsensitive)

-(void) setObject:(id) obj forCaseInsensitiveKey:(id)aKey {
    for (NSString *key in self.allKeys) {
        if ([key compare:aKey options:NSCaseInsensitiveSearch] == NSOrderedSame) {
            [self setObject:obj forKey:key];
            return;
        }
    }
    [self setObject:obj forKey:aKey];
}

@end

enjoy.

Sluggish answered 27/8, 2012 at 12:14 Comment(1)
What is bad about this way, is that you are eliminating the main advantage of dictionary - fast lookup. Search complexity increases from O(log(N))) to O(N).Photomap
D
4

Do you have control over the creation of the keys? If you do, I'd just force the keys to either lower or upper case when you're creating them. This way when you need to look up something, you don't have to worry about mixed case keys.

Downwards answered 26/5, 2011 at 7:29 Comment(4)
This is, by far, the easiest solution. Force the keys to upper or lower case on insertion and do the same on lookup. If you have overlap ("steve" and "Steve" are both valid keys), then this won't work.Hf
I didn't have control over creation of Key. The problem is combination of upper and lower case letter. I didn't have any idea to solve it.Help me in this issueDisruptive
Can you give me a little bit more context? Where is this dictionary coming from? Do you have any ideas about the keys that the dictionary contains?Downwards
For instance, some Dictionaries I'm working with are holding JSON data where the key is formulated from a REST response. So, this isn't an answer for every situation, although it is a good idea!Channel
S
2

You can do this to get the object as an alternative to subclassing.

__block id object;
[dictionary enumerateKeysAndObjectsWithOptions:NSEnumerationConcurrent 
                                    UsingBlock:^(id key, id obj, BOOL *stop){
    if ( [key isKindOfClass:[NSString class]] ) {
        if ( [(NSString*)key caseInsensitiveCompare:aString] == NSOrderedSame ) {
            object = obj; // retain if wish to.
            *stop = YES;
        }            
    }
}];

You can use a #define shorthand if you find yourself doing this a lot in your code.

Subcommittee answered 26/5, 2011 at 7:37 Comment(1)
A perfectly good solution as long as your dictionaries are relatively small and/or you aren't looking up keys that often. Never discount a seemingly inefficient solution until you have performance data indicating that it is a problem!Hf
D
1

Don't think there's any easy way. Your best option might be to create a subclass of NSMutableDictionary, and override the objectForKey and setObject:ForKey methoods. Then in your overridden methods ensure that all keys are converted to lowercase (or uppercase), before passing them up to the superclass methdods.

Something along the lines of the following should work:

@Interface CaseInsensitveMutableDictionary : MutableDictionary {}
@end

@implementation CaseInsensitveMutableDictionary
    - (void) setObject: (id) anObject forKey: (id) aKey {
       [super setObject:anObject forKey:[skey lowercaseString]];
    }

    - (id) objectForKey: (id) aKey {
       return [super objectForKey: [aKey lowercaseString]];
    }
@end
Disinherit answered 26/5, 2011 at 7:22 Comment(2)
Good idea, but you can't subclass *Dictionary that way; you'd have to implement the primitive methods in the class cluster.Hf
Hi, thanks for your feedback. If i inherit the nsmutabledictionary it will not violate rules of apple right?Disruptive

© 2022 - 2024 — McMap. All rights reserved.