有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java比较HashMap中的键和值

我有一个如下的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

然后,我使用值为153的键"the/at"

我为此编写的代码如下-

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

我的问题是——我能用更有效的方法完成同样的输出吗

谢谢


共 (4) 个答案

  1. # 1 楼答案

    创建一个新的

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

    这将把代币映射到它们的最大数量

    只需通过钥匙一次

    将每个密钥拆分为其组件令牌

    对于每个标记,请查看highMap。如果密钥不存在,请添加其计数。如果条目已存在,且当前计数大于上一个最大值,请替换映射中的最大值

    完成单次传递后,highCount将包含所有唯一的令牌,以及每个令牌的最高计数

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

  2. # 2 楼答案

    当前方法中最慢的部分是键的成对比较。首先,定义一个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中的键值,可以轻松地重建所需的输出

  3. # 3 楼答案

    算法的基本思想:

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

      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. 现在你应该有一张地图列表。表示所需条目的条目对象。复杂性应为n(对数n),并受排序算法的限制,而分组/收集项目的复杂性为n。

  4. # 4 楼答案

    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