NSDictionary类中有objectForKey方法,但是它对键名区分大小写。没有可用的函数可以像这样进行不区分大小写的查找。
- (id)objectForKey:(id)aKey options:(id) options;
在选项中,您可以传递“NSCaseInsensitiveSearch”参数。
要从大小写不敏感的NSDictionary中获取密钥,可以使用下面编写的以下代码。
NSDictionary类中有objectForKey方法,但是它对键名区分大小写。没有可用的函数可以像这样进行不区分大小写的查找。
- (id)objectForKey:(id)aKey options:(id) options;
在选项中,您可以传递“NSCaseInsensitiveSearch”参数。
要从大小写不敏感的NSDictionary中获取密钥,可以使用下面编写的以下代码。
- (id)objectForCaseInsensitiveKey:(NSString *)key {
NSArray *allKeys = [self allKeys];
for (NSString *str in allKeys) {
if ([key caseInsensitiveCompare:str] == NSOrderedSame) {
return [self objectForKey:str];
}
}
return nil;
}
O(log(N))
提高到了 O(N)
。 - ivanzoidO(1)
提升到了 O(n)
;NSDictionary
是一个哈希表,而不是一棵树。 - al45tair这里有几个原因不包括在内:
NSDictionary使用哈希相等,而对于任何良好的哈希算法,源字符串中的任何变化都会导致不同的哈希。
更重要的是NSDictionary的键不是字符串。符合NSCopying协议的任何对象都可以作为字典键,其中包括比字符串多得多的对象。NSNumber和NSBezierPath之间的大小写不敏感的比较会是什么样子?
这里的许多答案提供的解决方案都相当于将字典转换成数组并迭代它。那可行,如果你只需要一次性的话这没关系。但是该解决方案非常丑陋且具有糟糕的性能特征。如果我经常需要这个(例如足够创建一个NSDictionary类别),我会想要在数据结构级别上正确地解决它。
你需要的是一个类,它包装了一个NSDictionary,只允许使用字符串作为键,并在给定键时自动将其小写(如果需要双向映射,还可能记住原始键)。这将相当简单实现,并且是一个更清晰的设计。如果只需要一次性,那么这太麻烦了,但如果你经常这样做,我认为值得整洁地处理它。
NSString *foldedString(NSString *s, NSLocale *locale)
{
CFMutableStringRef ret = CFStringCreateMutableCopy(kCFAllocatorDefault, 0,
(__bridge CFStringRef)s);
CFStringNormalize(ret, kCFStringNormalizationFormD);
CFStringFold(ret, kCFCompareCaseInsensitive, (__bridge CFLocaleRef)locale);
return (__bridge_transfer NSString *)ret;
}
NULL
,则会获得当前系统语言环境。在大多数情况下,这是可以接受的,但是对于土耳其用户来说,他们可能会惊讶地发现“I”与“ı”相匹配,而不是“I”。因此,您可能需要传递[NSLocale currentLocale]
,如果您要保存结果,还可以保存区域标识符并从中创建区域设置。[dict setObject:obj forKey:foldedString(myKey, locale)];
并且再次查找
[dict objectForKey:foldedString(myKey, locale)];
最后一点观察是您可能希望将大小写折叠的键与原始值一起存储,这样您就不必在每次访问字典时都进行折叠。
NSDictionary *dic=[NSDictionary dictionaryWithObjectsAndKeys:@"John",@"Name",@"123456",@"empId", nil];
NSString *key=@"naMe";
NSString *name=[dic objectForKey:key];
if(name==nil){
NSPredicate *searchPred=[NSPredicate predicateWithFormat:@"self LIKE[cd] %@",key];
NSArray *searchedKeys=[[dic allKeys] filteredArrayUsingPredicate:searchPred];
if(searchedKeys.count>0){
name=[dic objectForKey:[searchedKeys objectAtIndex:0]];
}
}
NSLog(@"Name = %@",name);
O(n)
,然后必须解析 NSPredicate
并过滤结果数组。 - al45tair很多答案都是正确的,但这里有一个更好的例子:
NSDictionary* dict= @{ @"hello" : @"Hey" };
NSArray* keys= [dict allKeys];
NSUInteger index=[keys indexOfObjectPassingTest: ^BOOL (id obj, NSUInteger index, BOOL* stop)
{
if( [obj caseInsensitiveCompare: @"Hello"]==NSOrderedSame)
{
*stop= YES;
return YES;
}
else
{
return NO;
}
}];
就个人而言,我认为这种方式更容易,但每个人都有自己的编程风格。
编辑
一种不太易读但更短的解决方案:
NSDictionary* dict= @{ @"hello" : @"Hey" };
NSArray* keys= [dict allKeys];
NSUInteger index=[keys indexOfObjectPassingTest: ^BOOL (id obj, NSUInteger index, BOOL* stop)
{
return *stop= [obj caseInsensitiveCompare: @"Hello"]==NSOrderedSame ;
}];
O(n)
的答案。NSDictionary
访问是O(1)
的。至少我想它没有使用NSPredicate
。 - al45tair如果您只在一个地方(也许是两个或三个地方)将数据存储到NSDictionary中并从中检索数据,那么您可以在这两个地方使用
[myString lowercaseString]
更严谨的答案对于字典对象在代码中的多处使用非常有用。