2012-11-28 25 views
6

NSDictionaryにはobjectForKeyがありますが、キーには大文字です。オプションであなたはケースinsesitive 1は、下記の書かれた次のコードを使用することができますですNSDictionaryのからキーのを取得するにはNSDictionaryの大文字と小文字を区別しないobjectForKey:

を「NSCaseInsensitiveSearch」を渡すことができ

- (id)objectForKey:(id)aKey options:(id) options; 

のような利用可能ませ機能はありません。

+0

適切な正当な理由で賛辞をいただきました。 – andyPaul

+0

それは自分自身が答えて共有している質問です。 – andyPaul

+0

しかし、私は質問をするとき私は自分の質問に答えるのオプションを参照してください。それで、私は何をしたのですか。ところで、評判を得ることにあなたのコメントはかなり皮肉です。私は多くのコーディングスタイルを見て、@ラミーのように答えることもできます。あなたのブログを指定してください、私はそこにそのような質問をすることができます。 – andyPaul

答えて

8

これが理由のカップルのために含まれていません。

  1. NSDictionaryのは、ハッシュ平等を使用し、ためにほとんどすべての良いハッシュアルゴリズム、ソース文字列の任意のバリエーションは異なるハッシュになります。

  2. さらに重要なことに、NSDictionaryキーは文字列ではありません。 NSCopyingに準拠しているオブジェクトは、辞書キーとすることができ、それは文字列よりもはるかに多くを含みます。大文字と小文字を区別しないNSNumberとNSB​​ezierPathの比較はどのようになりますか?

ここでの回答の多くは、辞書を配列に変換して繰り返し処理するソリューションを提供しています。それはうまくいきます。もしあなたがワンオフとしてこれを必要とすれば、それはうまくいきます。しかし、その解決策はちょっと醜いですし、パフォーマンスの特性が悪いです。これが(NSDictionaryカテゴリを作成するのに十分なほど)たくさんのことが必要なものだったら、データ構造レベルで適切に解決したいと考えています。

NSDictionaryをラップするクラスは、キーの文字列を許可し、与えられたとおりにキーを自動的に小文字にします(双方向マッピングが必要な場合は元のキーも記憶することがあります)。これは実装が非常に簡単で、はるかにクリーンな設計です。一回限りでは重すぎますが、これがたくさんやっていることがあれば、きれいにやる価値があると思います。

+0

完璧な、これは本当に素晴らしい答えです。私はあなたのポイントに同意しますobjectForKey NSString常にされていないが、それは最も一般的に使用されます。これはobjectForKeyが呼び出されたときにシステムが関数に渡されたキーのハッシュを計算し、forループを実行してそのハッシュと利用可能なハッシュをマッチさせ、一致が見つかったときに値を返すと思います。間違っていれば私を修正してください。 – andyPaul

+0

@andyPaul:それより少し複雑です。そのアルゴリズムは、キーの値を見つけるために線形の時間がかかります(すなわち、辞書内の各追加項目がある程度のオーバヘッドを追加するため、キーや値との比較に平均して時間がかかる)が、NSDictionaryは数十万オブジェクトの。しかし、ハッシュを比較することで動作するという基本的な考え方はまさに正しいことです。 NSDictionaryは1つのクラスではありませんが、異なる実装を持つさまざまなクラスがすべて外部と同じに見えます) – Chuck

+0

ローケーションは正しい変換ではありません。折り畳みの場合。 – alastair

1

以下のコードでは、入力キーの実際のキーを検索します。したがって、入力キー= @ "naMe"の場合、実際のキー= @ "名前"です。 、

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 *dic=[NSDictionary dictionaryWithObjectsAndKeys:@"John",@"Name",@"123456",@"empId", nil]; 


NSString *[email protected]"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); 
+0

このようにすることもできます。 http://stackoverflow.com/questions/6135000/case-insensitive-search-in-nsmutabledictionary –

+0

これは複雑で低速です。辞書 'O(n)'のすべてのキーを含む配列を作成し、次に 'NSPredicate'を解析し、結果の配列をフィルタリングしなければなりません。 – alastair

12

あなたが

- (id)objectForCaseInsensitiveKey:(NSString *)key { 
    NSArray *allKeys = [self allKeys]; 
    for (NSString *str in allKeys) { 
     if ([key caseInsensitiveCompare:str] == NSOrderedSame) { 
      return [self objectForKey:str]; 
     } 
    } 
    return nil; 
} 
+0

カテゴリを作成することをお勧めします。しかし、なぜforループを書く必要がありますか? NSPredicateを使用する簡単に利用可能な関数を使用できます。 – andyPaul

+0

はい、あなたは正しいです。 @andyPaul – Siddiq

+8

...あなたはちょうど 'O(log(N))'から単に 'O(N)'に検索の複雑さを打ち砕いた。 – ivanzoid

0

多くの答えが正しいか、この機能をNSDictionaryのクラスのカテゴリーを追加する必要があるが、ここではより多くの例です。誰もが彼のプログラミングスタイルを持っています。

EDIT

読みにくくより短いソリューション:

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 ; 

    }]; 
+0

あなたが書いたコードの行数を見てください。しかし、はい、ブロック全体を1行に書くことはできますが、理解することは非常に難しいでしょう。 – andyPaul

+0

多くの行がありますが、コードの量は非常に少ないです。私は[obj caseInsensitiveCompare:@ "Hello"] == NSOrderedSameを返しません。値を返す前にYESを設定しなければならないからです。 –

+0

素晴らしい、私は私の答えに多くのコーディングスタイルを見つけた。 – andyPaul

0

一つだけの場所(多分2または3)で、NSDictionaryのをに格納し、そしてから取得している場合は、両方で

[のmyString lowercaseString]

を使用することができます。ディクショナリオブジェクトがコード全体で使用されている場合は、より厳密な答えが役立ちます。

+0

これは実際には上記の長いもののほうがずっと良い答えです。唯一の間違いは、小文字がすべてのケースで期待どおりに機能しないことです(実際には文字列を大文字にする必要があります)。 – alastair

1

正しい答えは、大文字と小文字を入れたキーを辞書キーとして使用することです。 これは大文字または小文字に変換するのと同じではないとO(1)平均ケース検索/挿入の複雑さを破棄しません。

残念ながら、Cocoaは文字列を大文字に変換するための適切なNSStringメソッドを持っていないようですが、そのためにCore FoundationにはCFStringFold()があります。のは、必要な作業を行うために、短い関数を書いてみましょう:

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」にマッチすることに驚くかもしれません。あなたはゆえ[NSLocale currentLocale]を渡したい、とあなたは結果あなたかもしれないを保存している場合も、ロケール識別子を保存し、それからロケールを作成することもできます。辞書に追加して、あなたが今

[dict setObject:obj forKey:foldedString(myKey, locale)]; 

を行うにして一つの最終観測はあなたが大文字小文字を保存したいかもしれないということです

[dict objectForKey:foldedString(myKey, locale)]; 

再び

をルックアップする必要があるので、

、キーを元の値と一緒に使用すると、辞書へのアクセスごとに折り畳む必要はありません。

関連する問題