繁体   English   中英

比较HashMap和Value中的键

[英]Comparing keys in HashMap and Values

我有一个HashMap如下-

HashMap<String, Integer> BC = new HashMap<String, Integer>();

它存储为键-“令牌/年龄”和值-“每个令牌/标签的频率”。

例-

"the/at" 153
"that/cs" 45
"Ann/np" 3

现在,我解析每个键,并检查同一令牌是否说“ the”是否与多个标签相关联,然后取两个标签中最大的一个。

例-

"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倍(加上更多)。

我的问题是-我可以使用更有效的方法完成相同的输出吗?

谢谢!

创建一个新的

Map<String,Integer> highCount = new HashMap<>();

会将令牌映射到最大数量。

一次通过按键。

将每个密钥分成其组件令牌。

对于每个令牌,请查看highMap 如果密钥不存在,请添加其数量。 如果条目已经存在并且当前计数大于先前的最大值,请替换映射中的最大值。

完成单遍操作后, highCount将包含所有唯一令牌以及每个令牌看到的最高计数。

注意:此答案旨在为您提供一个起点,以开发一个完整的解决方案。 关键概念是创建并填充从令牌到某种“值”类型(不一定只是Integer )的新映射,该映射可为您提供所需的功能。 值类型很可能是一个新的自定义类,用于存储标记和计数。

当前方法最慢的部分是由于密钥的成对比较。 首先,定义一个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; 
  } 
} 

因此,您可以尝试执行以下操作的算法:

  1. 初始化新的HashMap<String, Tuple<String, Integer>> result
  2. 给定旧地图中的输入对(key, value) ,其中key = "a/b" ,请检查result.keySet().contains(a)result.keySet().contains(b)
  3. 如果ab都不同时存在,则result.put(a, new Tuple<String, Integer>(b, value)result.put(b, new Tuple<String, Integer>(a, value))
  4. 如果a存在时,比较valuev = result.get(a) 如果value > v ,则从result删除ab并执行步骤3。对b进行相同操作。 否则,获取下一个键值对。

遍历旧的哈希映射并插入所有内容之后,可以通过转换result的键值轻松地重建所需的输出。

关于算法的基本思想:

  1. 您应该获取HashMap的entrySet()并将其转换为List:

     ArrayList<Map.Entry<String, Integer>> list = new ArrayList<>(map.entrySet()); 
  2. 现在,您应该按字母顺序对列表进行排序。 我们这样做是因为HashMap没有顺序,因此您可以期望相应的键可能相距很远。 但是通过对它们进行排序,所有相关的键都直接相邻。

     Collections.sort(list, Comparator.comparing(e -> e.getKey())); 

    由于按字母顺序排序,条目“ the / at”和“ the / det”将彼此相邻。

  3. 现在,您可以在记住最佳项目的同时遍历整个列表,直到找到一个更好的项目,或者找到前缀不相同的第一个项目(例如“ the”)。

     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); 
  4. 现在,您应该具有一个代表所需条目的Map.Entry对象列表。 复杂度应为n(log n),并受排序算法限制,而分组/收集项的复杂度为n。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM