6

.javaファイルからJavaキーワードをキャプチャし、マップを使用して発生を追跡するプロジェクトを作成しています。私は過去に同様の方法をうまく使用しましたが、ここでの使用目的にこの方法を採用することはできないようです。

    Map<String,Integer> map = new TreeMap<String,Integer>();
    Set<String> keywordSet = new HashSet<String>(Arrays.asList(keywords));
    Scanner input = new Scanner(file);
    int counter = 0;
    while (input.hasNext())
    {
        String key = input.next();
        if (key.length() > 0)
        {
            if (keywordSet.contains(key))
            {
                map.put(key, 1);
                counter++;
            }

                if(map.containsKey(key)) <--tried inner loop here, failed
                {
                    int value = map.get(key);
                    value++;
                    map.put(key, value);
                }

        }

このコードブロックは、キーワードをキーに追加し、同じキーが発生するたびに値をインクリメントすることになっています。これまでのところ、キーワードは追加されていますが、値を適切にインクリメントできません。出力例は次のとおりです。

{assert=2, class=2, continue=2, default=2, else=2, ...} 

基本的に、想定されている値ではなく、マップ内のすべての値をインクリメントします。私はこれを考えすぎているのか、それとも何を考えているのかわかりません。私は内側のループを試しましたが、それは私に非常識な結果をもたらしました。私は本当にこれを考えすぎていることを願っています。どんな助けでも大歓迎です!

4

5 に答える 5

13

あなたが望むものを達成するためのはるかに簡潔な(そして推論しやすい)方法があります:

final ConcurrentMap<String, AtomicInteger> map = new ConcurrentHashMap<>();
final Scanner input = new Scanner(file);
while (input.hasNext()) {
  final String key = input.next();
  if (key.length() > 0) {
    map.putIfAbsent(key, new AtomicInteger(0));
    map.get(key).incrementAndGet();
  }
}

これが機能する理由を分析してみましょう。

キーワードに遭遇するときはいつでも、Scanner2つの可能性のあるケースがあります:あなたが以前にそれを遭遇した(すなわち、それは既知のキーワードである)か、それはまだ見えないキーワードです。

  • 見えないキーワードの場合:マップputIfAbsentAtomicInteger値0incrementAndGet()を設定し、直後に1に設定します。これ以降、既知のキーワードになります;
  • 既知のキーワードの場合:putIfAbsentは何もせず、incrementAndGet()マップにすでに存在する値をインクリメントします。

次に、キーセットが必要な場合は、次のようにします。

final Set<String> keys = map.keySet();

すべての値を出力するには、次のようにします。

for (final String k : map.keySet()) {
  System.out.println(k + ": " + map.get(k).get());
}

ConcurrentMap上記で使用した2つの「異なる」クラスとを使用する必要はありませんAtomicInteger。自分で書き込もうとした(そして失敗した)ロジックの多くをカプセル化するため、使いやすくなっています。それらがカプセル化するロジックは、他のすべての回答が説明しているものとまったく同じです(つまり、値が存在するかどうかをテストし、0に設定されていない場合は、存在する値を取得し、インクリメントしてマップに戻します)。

マップのキー(単語がカウントされている)をアルファベット順に維持するには、ConcurrentNavigableMapなどを使用しConcurrentSkipListMap ます。

于 2013-03-05T06:49:48.293 に答える
7

スキャンするすべてのキーについて、マップに新しいエントリを作成します(既存のエントリを上書きします)。次に、次の条件が成立するため、カウントを1ずつインクリメントして、値2に到達します。

内側の部分は次のようになります。

        if (keywordSet.contains(key))
        {
            Integer value = map.get(key);
            if (value == null)
                value = 0;
            value++;
            map.put(key, value);
        }

とにかく、これをより効率的にするために、ある種の可変整数を使用することを検討してください。マップ内のエントリを上書きする必要はなく、整数のボクシング操作をあまり行う必要もありません。

于 2013-03-05T06:50:37.173 に答える
6

Map.merge(Java 8以降)を使用するとさらに簡潔になります。

if (keywordSet.contains(key)) {
    map.merge(key, 1, (currentCount, notUsed) -> ++currentCount);
}

カウントマップの一般的な実装は次のとおりです。キーのカウントを表す値を持つマップです。

public static <K> void count(K key, Map<K, Integer> map) {
    map.merge(key, 1, (currentCount, notUsed) -> ++currentCount);
}

public static void main(String[] args) {
    Map<String, Integer> map = new HashMap<>();
    count("A", map);
    count("B", map);
    count("A", map);
    count("Z", map);
    count("A", map);
    System.out.println(map); // {A=3, B=1, Z=1}
}
于 2015-07-07T09:34:21.027 に答える
2

常に値を1に設定してから、別の値で更新します。必要なのは、マップ値を更新することです(そして、それを再び1に設定しないでください)。

それ以外の:

map.put(key, 1);

使用する:

Integer value = map.get(key);
if (value == null){
    value = 0
}
value++;
map.put(key, value);

そして、2番目の場合をドロップします。

于 2013-03-05T06:51:03.593 に答える
1
Map<String, Integer> map = new HashMap<String, Integer>();
Set<String> keywordSet = new HashSet<String>(Arrays.asList(keywords));
Scanner input = new Scanner(file);

while (input.hasNext()){
     String key = input.next();
     if (key.length() > 0)
        if (keywordSet.contains(key)){
           Integer counter = map.get(key);

           if (counter == null)
               map.put(key, 1);
           else
               map.put(key, count + 1);
         }
}
于 2013-03-05T06:56:37.987 に答える