【问题标题】:Getting all the substrings as keys and their occurcences as values with hashmap使用 hashmap 将所有子字符串作为键并将它们的出现作为值
【发布时间】:2017-06-12 18:18:50
【问题描述】:

问题:给定一个字符串,我想使用Hash Map获取length = k的所有子字符串。

所以我声明了一个public static function getHistogram,它返回Map<String,Integer>,我正在尝试使用一个HashMap来获取该给定字符串的所有子字符串(作为键),以及已经出现在字符串,我想增加其键中的值(将是计数器)。

这是我目前得到的结果:当前输出: 输出不符合预期。

  import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Iterator;
import java.util.Set;

public class Main2{

    public static void main(String[] args) throws InvalidValueException{
        // Get a set of the entries
          Set set = Main2.getHistogram("ababaca", 5).entrySet();

          // Get an iterator
          Iterator i = set.iterator();

          // Display elements
          while(i.hasNext()) {
             Map.Entry me = (Map.Entry)i.next();
             System.out.print(me.getKey() + ": ");
             System.out.println(me.getValue());
          }
          System.out.println();
    }

    public static Map<String,Integer> getHistogram(String str, int k)
        throws InvalidValueException
    {
        int i,j;
        String tempStr;

        Map<String, Integer> hmap = new HashMap<String, Integer>();
        for(i = 0; i < str.length(); i++)
          {
            for(j=i; j < str.length(); j++){
                tempStr = str.substring(i, j);
                int count = hmap.containsKey(tempStr) ? hmap.get(tempStr) : 0;
                hmap.put(tempStr, count + 1);
            }

          }
        return hmap;    
    }
}

编辑:必须使用 count + 1 而不是 count++,但仍未完全修复。

输出:

: 7
a: 3
ab: 2
aba: 2
b: 2
bab: 1
ac: 1
c: 1
bac: 1
abac: 1
abab: 1
baba: 1
babac: 1
ababa: 1
ababac: 1
ba: 2

【问题讨论】:

  • “长度为 k”,但我没看到,k 在哪里使用
  • @matoni 我知道,它没有被使用,因为我想先得到所有的长度,当我成功时,我会相应地编辑它。
  • 那么在从地图中过滤掉所有长度为 k 的子字符串之前,预期的行为是什么?
  • @matoni 正如我在上一条评论中提到的,我想输出给定字符串中的所有子字符串及其出现次数。

标签: java string hashmap


【解决方案1】:
public class Substr {
    public static void main(String[] args) {
        System.out.println(getHistogram("ababaca", 5));
        System.out.println(getHistogram("ababaca", 4));
        System.out.println(getHistogram("ababaca", 3));
        System.out.println(getHistogram("ababaca", 2));
        System.out.println(getHistogram("ababaca", 1));
    }

    public static Map<String, Integer> getHistogram(String str, int k) {
        Map<String, Integer> hmap = new HashMap<>();
        for (int start = 0; start < str.length() - k + 1; start++) {
            String substring = str.substring(start, start + k);
            int count = hmap.containsKey(substring) ? hmap.get(substring) : 0;
            hmap.put(substring, count + 1);
        }
        return hmap;
    }    
}

这似乎产生了正确的结果。

如果k 是固定的,则不需要两个循环,只需一个。它只是遍历可能子字符串的开始索引。然后我们按照您最初的建议获取子字符串并计算子字符串的数量。

【讨论】:

  • 你是对的。我的实现走得太远了。谢谢罗马/
【解决方案2】:

使用 Java 8,您可以通过简单的方式做到这一点:

public static Map<String, Long> getHistogram(String string, int k) {
    return 
        k > string.length() ? Collections.emptyMap() :
        k == string.length() ? Collections.singletonMap(string, 1L) :
            IntStream.range(0, string.length() - k + 1)
                .mapToObj(i -> string.substring(i, i + k))
                .collect(Collectors.groupingBy(
                    Function.identity(),
                    Collectors.counting()));
}

这首先检查k 是否大于给定string 的长度。如果k 更大,它返回一个空映射(你也可以抛出一个IllegalArgumentException)。

然后,它检查k 是否等于给定string 的长度,在这种情况下,将返回一个带有string1L 的单例映射。

最后,如果k &lt; string.length(),我们创建一个从0(包括)到string.length() - k + 1(不包括)的整数范围。然后,这些整数中的每一个都被转换为从stringi-th 位置开始的子字符串,并且 always 采用k 字符。 (这与您的实现不同,在第一次迭代中使用0 字符,在第二次迭代中使用1 等)。如果我正确理解了您的问题,您将始终需要使用 k 字符,直到到达 string 的末尾。

然后,所有这些子字符串通过Collectors.groupingBy 收集器收集到Map,该收集器需要一个将流的每个元素(在您的情况下是子字符串)映射到映射键的函数。由于我们希望实际的子字符串成为映射的键,因此我使用了标识函数。 Collectors.counting 只是将每个子字符串的计数作为值。

如果您希望子字符串以它们从string 中获取的顺序出现,您可以使用接受地图供应商的Collectors.grouping 版本,并告诉它使用LinkedHashMap,它保留插入顺序:

public static Map<String, Long> getHistogram(String string, int k) {
    return
        k > string.length() ? Collections.emptyMap() :
        k == string.length() ? Collections.singletonMap(string, 1L) :
            IntStream.range(0, string.length() - k + 1)
                .mapToObj(i -> string.substring(i, i + k))
                .collect(Collectors.groupingBy(
                    Function.identity(),
                    LinkedHashMap::new, // <-- here's the map supplier
                    Collectors.counting()));
}

【讨论】:

  • 这是一个很好的解决方案 Federico。但我宁愿坚持更容易理解的实现。谢谢!
  • @IlanAizelmanWS 不用担心,我的回答只是补充了 Roman 的回答。现在读者将有两种方法来解决您发布的问题。
猜你喜欢
  • 2013-05-07
  • 2022-01-24
  • 2016-01-14
  • 2014-11-30
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 1970-01-01
  • 2013-11-17
相关资源
最近更新 更多