2011-07-15 26 views
22

私は電話帳のようなものを作成する必要があります。それは名前&の番号を含んでいます。文字を入力すると、リストが返されます。以下の例では、Hをタイプすると、Harmer、Harris、Hawken、Hoslerを含むリストが返されます。タイプがHaのときは、Harmer、Harris、Hawkenだけを含むリストを返すべきです。ハッシュマップの部分検索

Map<String, String> nameNum = new HashMap<String, String>(); 

    nameNum.put("Brown", "+1236389023"); 
    nameNum.put("Bob", "+1236389023"); 
    nameNum.put("Harmer", "+1236389023"); 
    nameNum.put("Harris", "+1236389023"); 
    nameNum.put("Hawken", "+1236389023"); 
    nameNum.put("Hosler", "+1236389023"); 

どのように達成できますか? ありがとうございます。

+0

はあなたがすべてで 'HashMap'を使用すると、このような何かのために良い考えであることを確認していますか?私は別のデータ構造が良いかもしれないと思います。 –

+0

最初の文字のみを探しているのですか、入力するとリストが削除されますか?例えば、 "Ha"の入力は "Hosler"を排除しますか? –

答えて

25

ええ、HashMapはこれに適したデータ構造ではありません。ボゾが言ったように、Trieが正しいでしょう。

Javaのオンボードツールと

、TreeMapの(または任意のSortedMapは、実際に)使用することができます

public <V> SortedMap<String, V> filterPrefix(SortedMap<String,V> baseMap, String prefix) { 
    if(prefix.length() > 0) { 
     char nextLetter = prefix.charAt(prefix.length() -1) + 1; 
     String end = prefix.substring(0, prefix.length()-1) + nextLetter; 
     return baseMap.subMap(prefix, end); 
    } 
    return baseMap; 
} 

出力であってもキーでソートされます。ここで

使用例:

SortedMap<String, String> nameNum = new TreeMap<String, String>(); 
// put your phone numbers 

String prefix = ...; 
for(Map.Entry<String,String> entry : filterPrefix(nameNum, prefix).entrySet()) { 
    System.out.println(entry); 
} 

あなたのプレフィックスフィルターは、ケースの違いに応じたこと(適度な強度設定でCollator、またはString.CASE_INSENSITIVE_ORDERのような)あなたのマップに適したコンパレータを使用しないようにしたい場合。

+2

+1正しい考え。大文字小文字の問題も考慮してください。 –

+0

@PaŭloEbermann:なぜTrie、スペースを節約するのですか{http://stackoverflow.com/questions/8265476/trie-saves-space-but-how}? –

+0

接頭辞+ "\ uffff"を最後に使用することもできます。 – Tires

9

これは、Trieデータ構造を必要とします。 Javaの実装については、this questionを参照してください。私はthis oneを使用しました。

+0

ありがとうBozhoあなたのリンクは便利でした!しかし、その質問から約3年が終わりました。あなたが気付いている可能性のあるより良い解決策はありますか? –

+0

http://code.google.com/p/patricia-trie/私はそれを使用しました – Bozho

0

すべてをマルチマップに入れます(または、ListをHashMapの値として保存するだけです)。 "ブラウン" の場合、店舗:

"B"->["Brown"] 
"BR"->["Brown"] 
"BRO"->["Brown"] 

後で "ブラッドリー" を追加した場合:

"B"->["Brown", "Bradley"] 
"BR"->["Brown", "Bradley"] 
"BRO"->["Brown"] 
"BRA"->["Bradley"] 

等...

その後、 "ブラウン" や "ブラッドリー" をマッピングするための別のマップを持っています電話番号に。

+0

このデータ構造から物事を追加したり取り除いたりするのは非常にコストがかかります。 –

+0

私は同意します。しかし、私たちは彼の "電話帳のようなもの"がどれほど大きいか分からない。私は単純なものを最初に行い、後で最適化することを好む。これは最も簡単なことのようです。 – dgrant

+0

アクセスはO(1)ですが、ツリーの場合はlog(n)になります。あなたがオートコンプリートのようなことをしているなら、それはもっと重要ではありませんか?また、データセットの更新頻度はどのくらいですか?取得がずっと頻繁に行われている場合、追加/削除の遅さが気になる人がいます。そして、ここでの追加と削除はそれほど悪くはないと私は考えていません。 – dgrant

-1

guava Multimapを使用すると、ソリューションが簡単になります。

キーは名前の最初の文字で、値はキーで始まるすべての名前と電話のペア(最初の文字)を含むCollectionです。

例:

public void test(){ 
     //firstLetter -> list of name-phone pair 
     Multimap<String, Pair> mMap = ArrayListMultimap.create(); 

     put(mMap, "Brown", "+1236389023"); 
     put(mMap, "Bob", "+1236389023"); 
     put(mMap, "Harmer", "+1236389023"); 
     put(mMap, "Harris", "+1236389023"); 
     put(mMap, "Hawken", "+1236389023"); 
     put(mMap, "Hosler", "+1236389023"); 

     //Test 
     System.out.println(mMap.get("H")); 
    } 

    void put(Multimap<String, Pair> mMap, String name, String phone){ 
     mMap.put(name.substring(0,1), new Pair(name, phone)); 
    } 

    public static class Pair{ 
     String name; 
     String phone; 

     public Pair(String name, String phone) { 
     this.name = name; 
     this.phone = phone; 
     } 

     @Override 
     public String toString() { 
     return "Pair [name="+name+", phone="+phone+"]"; 
     } 

}

関連する問題