簡體   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