我有一个HashMap<String, Integer> vocabulary
,其中包含单词及其权重(不重要,此处仅字符串很重要):
vocabulary = ["this movie"=5, "great"=2, "bad"=2, ...]
和一个标记字符串作为列表:
String str = "this movie is great";
List<String> tokens = tokenize(str) // tokens = ["this", "movie", "is", "great", "this movie", "is great", ...]
现在,我需要一种快速的方法来为此标记化字符串创建一个向量,该向量计算词汇表的每个条目,该词在标记化字符串中的出现次数
HashMap<String, Integer> vec = new HashMap();
Iterator it = vocabulary.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry) it.next();
String word = (String) pair.getKey();
int count = 0;
for (String w : tokens) {
if (w.equals(word)) {
count += 1;
}
}
vec.put(word, count);
}
所以
vec
应该是["this movie"=1, "great"=1, bad = 0]
有更好的执行方法吗?我在更大的范围内遇到了性能问题,并假设此问题必须在此处,因为词汇量大约有300'000个条目。普通的标记化文本包含大约100个单词。
词汇表是hashMap是否存在问题?
最佳答案
计算tokens
每个元素的出现次数:
Map<String, Long> tokensCount = tokens.stream().collect(
Collectors.groupingBy(Function.identity(), Collectors.counting()));
然后,只需从此地图中查找即可,而不是从内部循环中查找:
count = tokensCount.getOrDefault(word, 0L).intValue();
这更快,因为在映射中的查找为O(1),而迭代
tokens
寻找相等的元素为O(#令牌)。还要注意,除了获取密钥之外,您没有使用
pair
,因此可以迭代vocabulary.keySet()
,而不是vocabulary.entrySet()
。另外,如果您不使用原始迭代器,则不需要显式强制转换:
Iterator<Map.Entry<String, Integer>> it = ...
编辑,现在您已经添加了两个集合的相对大小:
您可以简单地迭代
tokens
,然后查看vocabulary
是否包含以下内容:Map<String, Integer> vec = new HashMap<>();
for (String token : tokens) {
if (vocabulary.contains(token)) {
vec.merge(token, 1, (old,v) -> old+v);
}
}