3

すでに多くの質問が寄せられていることは承知していますが、キャッチするためにもう 1 つ質問を投げかけています。配列には膨大な量 (数千のレコード) のデータが含まれてNSDictionaryいます。辞書のキー内で検索を配列に実行しようとしています。

UITextField - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string; データソース方式で検索を行っているのですが、

私の検索要件は文字列全体であり、

文字列の例、

aaa、abeb、abcd、abbec のような文字列

検索の流れ、

aすべての文字列を返す場合、

aaaaa のみを返す場合、

のようにab返されたabeb, abcd, abbec場合、

重要、そのcd場合のみ abcd を返す場合

これらの方法で試してみましたが、

NSPredicate の使用

NSLog(@"start search at : %@",[NSDate date]);
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Name contains[cd] %@", matchString];
searchArray = [[meadArray filteredArrayUsingPredicate:predicate] mutableCopy];
NSLog(@"Search found count = %d",searchArray.count);
[tableCheck reloadData];
NSLog(@"End search at : %@",[NSDate date]);

別の方法 -反復を通じて、

NSLog(@"start search at : %@",[NSDate date]);
for (NSDictionary *word in arrayNames)
{
    if ([matchString length] == 0)
    {
        [searchArray addObject:word];
        continue;
    }
    NSRange lastRange = [[[word valueForKey:@"Name"] uppercaseString] rangeOfString:upString];

    if ( lastRange.location != NSNotFound)
    {
        if(range.location == 0 || lastRange.location == 0)
        {
            [searchArray addObject:word];
        }
    }
}    
NSLog(@"End search at : %@",[NSDate date]);

どちらの方法も問題なく機能し、期待どおりの結果が得られましたが、シミュレーターでのみ! デバイスで同じことをテストすると、検索の拡張に応じて約 1 / 2 / 3 秒かかります。最初に入力すると、a3 秒かかり、aa約 2 秒かかります。IT LOOKS CLUMSY ON DEVICE, ANY PRESSED KEY WILL BE REMAIN HIGHLIGHTED UNTIL SEARCH NOT DONE.

私が使用しているのと同じ方法または他の代替手段を使用して、さらに高速な検索を実行できる方法はありますか?

更新 1

CFArrayBSearchValuesも試してみました 検索文字列のインデックスのみを返しますが、一致するすべての文字列を返すものが必要です。

unsigned index = (unsigned)CFArrayBSearchValues((CFArrayRef)meadArray, CFRangeMake(0, CFArrayGetCount((CFArrayRef)meadArray)), (CFStringRef)matchString,(CFComparatorFunction)CFStringCompare, NULL);

更新 2

Alladinianコメントによると、バックグラウンド スレッドで検索操作を実行しました。はい、UI をロックしていませんが、それでも検索が遅すぎます。私が行っているのは、0.25 秒程度の遅延でセレクターを実行し、以前のセレクター呼び出しもキャンセルすることです。 、バックグラウンドで検索を実行し、メインスレッドでテーブルをリロードします。そのように動作します。少し遅れて文字を入力するとうまく機能しますが、単語全体を一度に入力すると、押された文字に従ってテーブルをロード/更新し、最後に実際の出力が表示されます.3-かかります実際のコンテンツを表示するのに 4 秒。

どんな提案や助けも大歓迎です!

4

5 に答える 5

1

いくつかのプロジェクトでsqlite の全文検索モジュールを使用しましたが、非常にうまく機能します。独自のコンパイル済みバージョンの sqlite を提供する必要がありますが、これには少し注意が必要ですが、プロセス全体についてはこちらで説明しています。

何をする必要があるかによって、このデータベースに事前入力するか、受け取ったデータを挿入するか、または両方の組み合わせを使用することができます。自分でソリューションをプログラムしようとするのは興味深い作業ですが、sqlite FTS に既に存在するアルゴリズムを再発明することになります。

入力と同時に検索を行っている場合は、操作がバックグラウンドで適切にキューに入れられていること、および操作がキャンセル可能であることを確認する必要があります。これを実行するには多くの方法があります。非常に人気のあるものは NSOperation を使用します

お役に立てれば。

于 2013-03-10T02:48:42.340 に答える
1

この答えは次anktasticの答えです。誰かが私たちが多くの努力をした解決策を直接得るので、私も私の答えを追加しています:)

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{
    //Cancel any previous selector calls
    [NSRunLoop cancelPreviousPerformRequestsWithTarget:self];

        if(string.length > 0)
        {
            NSString *str = [txt1.text substringToIndex:[txt1.text length] - 1];
            //delay is useful in smooth search - if you're performing web service calls for searching on cloud, then you should give delay as per your test
            [self performSelector:@selector(startSearch:) withObject:str afterDelay:0.05f];
        }
    }
}

- (void) startSearch:(NSString *)matchString
{
    //Cancel any previous operation added in queue
    [queue cancelAllOperations];
    //Create new operation
    NSInvocationOperation* operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(search:) object:matchString];
    [queue addOperation:operation];
}

- (void) search:(NSString *)matchString
{
    //Performing search operation
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Name contains[cd] %@", matchString];
    searchArray = [[meadArray filteredArrayUsingPredicate:predicate] mutableCopy];
    //only call again after any previous reload done
    [self performSelectorOnMainThread:@selector(reloadInMainThread) withObject:nil waitUntilDone:YES];
}

- (void) reloadInMainThread 
{
    //Reloading table in main thread for instance search effect
    [tableCheck reloadData];
}
于 2013-03-11T06:53:47.437 に答える
0

大文字と小文字を区別しない文字列の比較は、大文字と小文字を区別する比較よりも遅くなります。uppercaseNameディクショナリに追加のキーとして(またはsqliteテーブルの追加の列として)格納し、述語を次のように変更できます。

[NSPredicate predicateWithFormat:@"uppercaseName CONTAINS %@", [matchString uppercaseString]]
于 2013-03-09T09:03:22.947 に答える
0

配列/辞書の文字列は変更されますか? そうでない場合は、辞書内のすべてのキーを単一の配列に抽出することをお勧めします。検索する前にこれを行います。これを行う必要があるのは 1 回だけです。

私があなたの質問を誤解していなければ、私の提案は次のようなものです:

NSArray *arrayOfDicts = /*the array with dictionarys you have*/

NSMutableArray *allKeys = [NSMutableArray array]

for (NSDictionary *d in arrayOfDicts) {
     for (NSString *key in d) {
          [allKeys addObject:key];
     }
}

次に allKeys 配列を検索します。

于 2013-03-07T11:31:59.533 に答える