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();
  }
}

让我们分析一下为什么会这样。

每当Scanner遇到关键字时,有两种可能的情况:您以前遇到过(即,它是已知关键字),或者它是尚未见过的关键字

  • 如果它是一个看不见的关键字putIfAbsent将在地图中放置一个AtomicInteger值为 0 的值,然后incrementAndGet()将其设置为 1,从现在开始,它成为一个已知的关键字
  • 如果它是一个已知的关键字:putIfAbsent将什么都不做,并且incrementAndGet()会增加地图中已经存在的值。

然后,如果您想要密钥集,请执行以下操作:

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

要打印所有值,您可以执行以下操作:

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

您不会被迫使用我在上面使用的两个“不同”类,ConcurrentMap并且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);

并放弃第二个如果。

于 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 回答