我有一个HashMap如下 -
HashMap<String, Integer> BC = new HashMap<String, Integer>();
存储为键 - “标记/标记”和值 - “每个标记/标记的频率”。
实施例 -
"the/at" 153
"that/cs" 45
"Ann/np" 3
我现在解析每个键并检查相同的令牌是否说“是”它是否与多个标签相关联,然后取两者中最大的一个。
实施例 -
"the/at" 153
"the/det" 80
然后我带上关键字"the/at"
,价值为153
。
我编写的代码如下 -
private HashMap<String, Integer> Unigram_Tagger = new HashMap<String, Integer>();
for(String curr_key: BC.keySet())
{
for(String next_key: BC.keySet())
{
if(curr_key.equals(next_key))
continue;
else
{
String[] split_key_curr_key = curr_key.split("/");
String[] split_key_next_key = next_key.split("/");
//out.println("CK- " + curr_key + ", NK- " + next_key);
if(split_key_curr_key[0].equals(split_key_next_key[0]))
{
int ck_v = 0, nk_v = 0;
ck_v = BC.get(curr_key);
nk_v = BC.get(next_key);
if(ck_v > nk_v)
Unigram_Tagger.put(curr_key, BC.get(curr_key));
else
Unigram_Tagger.put(next_key, BC.get(next_key));
}
}
}
}
但是这段代码的计算时间太长,因为原来的HashMap'BC'有68442个条目,大约是它的平方= 4684307364次(加上一些)。
我的问题是 - 我可以使用更有效的方法完成相同的输出吗?
谢谢!
答案 0 :(得分:2)
制作新的
Map<String,Integer> highCount = new HashMap<>();
会将令牌映射到最大数量。
一键通过。
将每个键拆分为其组件标记。
对于每个令牌,请查看highMap
。如果密钥不存在,请添加其计数。如果条目已存在且当前计数大于先前的最大值,则替换地图中的最大值。
完成单次传递后,highCount
将包含所有唯一令牌以及每个令牌所见的最高次数。
注意:此答案旨在为您提供开发完整解决方案的起点。关键的概念是,您可以创建一个新地图,从令牌填充到某种“值”类型(不一定只是Integer
),为您提供所需的功能。很可能值类型将是一个新的自定义类,用于存储标记和计数。
答案 1 :(得分:0)
当前方法中最慢的部分是由于键的成对比较。首先,定义一个Tuple
类:
public class Tuple<X, Y> {
public final X x;
public final Y y;
public Tuple(X x, Y y) {
this.x = x;
this.y = y;
}
}
因此,你可以尝试一种算法:
HashMap<String, Tuple<String, Integer>> result
(key, value)
,其中key = "a/b"
,检查result.keySet().contains(a)
和result.keySet().contains(b)
。 a
和b
都不存在,result.put(a, new Tuple<String, Integer>(b, value)
和result.put(b, new Tuple<String, Integer>(a, value))
a
,请比较value
和v = result.get(a)
。如果value > v
,请从a
移除b
和result
并执行第3步。对b
执行相同操作。否则,获取下一个键值对。 在遍历旧哈希映射并插入所有内容之后,您可以通过转换result
中的键值来轻松地重建所需的输出。
答案 2 :(得分:0)
算法的基本思路:
您应该获取HashMap的entrySet()并将其转换为List:
ArrayList<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet());
现在您应该按字母顺序按键对列表进行排序。我们这样做是因为HashMap没有顺序,因此您可以预期相应的键可能相距很远。但是通过对它们进行排序,所有相关的键都是直接相邻的。
Collections.sort(list, Comparator.comparing(e -> e.getKey()));
条目&#34; / at&#34;和&#34; / det&#34;由于按字母顺序排序,它们将彼此相邻。
现在,您可以在记住最佳项目的同时迭代整个列表,直到找到更好的项目,或者找到第一个没有相同前缀的项目(例如&#34;&#34;)。
ArrayList<Map.Entry<String, Integer>> bestList = new ArrayList<>();
// The first entry of the list is considered the currently best item for it's group
Map.Entry<String, Integer> currentBest = best.get(0);
String key = currentBest.getKey();
String currentPrefix = key.substring(0, key.indexOf('/'));
for (int i=1; i<list.size(); i++) {
// The item we compare the current best with
Map.Entry<String, Integer> next = list.get(i);
String nkey = next.getKey();
String nextPrefix = nkey.substring(0, nkey.indexOf('/'));
// If both items have the same prefix, then we want to keep the best one
// as the current best item
if (currentPrefix.equals(nextPrefix)) {
if (currentBest.getValue() < next.getValue()) {
currentBest = next;
}
// If the prefix is different we add the current best to the best list and
// consider the current item the best one for the next group
} else {
bestList.add(currentBest);
currentBest = next;
currentPrefix = nextPrefix;
}
}
// The last one must be added here, or we would forget it
bestList.add(currentBest);
现在您应该有一个表示所需条目的Map.Entry对象列表。复杂度应为n(log n)并受排序算法的限制,而对项目进行分组/收集的复杂度为n。
答案 3 :(得分:0)
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import java.util.stream.Collectors;
public class Point {
public static void main(String[] args) {
HashMap<String, Integer> BC = new HashMap<>();
//some random values
BC.put("the/at",5);
BC.put("Ann/npe",6);
BC.put("the/atx",7);
BC.put("that/cs",8);
BC.put("the/aty",9);
BC.put("Ann/np",1);
BC.put("Ann/npq",2);
BC.put("the/atz",3);
BC.put("Ann/npz",4);
BC.put("the/atq",0);
BC.put("the/atw",12);
BC.put("that/cs",14);
BC.put("that/cs1",16);
BC.put("the/at1",18);
BC.put("the/at2",100);
BC.put("the/at3",123);
BC.put("that/det",153);
BC.put("xyx",123);
BC.put("xyx/w",2);
System.out.println("\nUnsorted Map......");
printMap(BC);
System.out.println("\nSorted Map......By Key");
//sort original map using TreeMap, it will sort the Map by keys automatically.
Map<String, Integer> sortedBC = new TreeMap<>(BC);
printMap(sortedBC);
// find all distinct prefixes by spliting the keys at "/"
List<String> uniquePrefixes = sortedBC.keySet().stream().map(i->i.split("/")[0]).distinct().collect(Collectors.toList());
System.out.println("\nuniquePrefixes: "+uniquePrefixes);
TreeMap<String,Integer> mapOfMaxValues = new TreeMap<>();
// for each prefix from the list above filter the entries from the sorted map
// having keys starting with this prefix
//and sort them by value in descending order and get the first which will have the highst value
uniquePrefixes.stream().forEach(i->{
Entry <String,Integer> e =
sortedBC.entrySet().stream().filter(j->j.getKey().startsWith(i))
.sorted(Map.Entry.comparingByValue(Comparator.reverseOrder())).findFirst().get();
mapOfMaxValues.put(e.getKey(), e.getValue());
});
System.out.println("\nmapOfMaxValues...\n");
printMap(mapOfMaxValues);
}
//pretty print a map
public static <K, V> void printMap(Map<K, V> map) {
map.entrySet().stream().forEach((entry) -> {
System.out.println("Key : " + entry.getKey()
+ " Value : " + entry.getValue());
});
}
}
// note: only tested with random values provided in the code
// behavior for large maps untested