簡體   English   中英

覆蓋位於ArrayList <String>中的HashMap中的值

[英]Overwriting values in a HashMap that are in an ArrayList<String>

假設我有一個帶字符串鍵和整數值的HashMap:

map = {cat=1, kid=3, girl=3, adult=2, human=5, dog=2, boy=2}

我想通過將此信息放入另一個HashMap來切換鍵和值。 我知道HashMap不能有重復的鍵,因此我嘗試將信息放入帶有Integer的HashMap中,用於映射到String ArrayList的鍵,這樣我就可以將一個Integer映射到多個字符串:

swap = {1=[cat], 2=[adult, dog, boy], 3=[kid, girl], 5=[human]}

我嘗試了以下代碼:

HashMap<Integer, ArrayList<String>> swap = new HashMap<Integer, ArrayList<String>>();

for (String x : map.keySet()) {
        for (int i = 0; i <= 5; i++) {
            ArrayList<String> list = new ArrayList<String>();
            if (i == map.get(x)) {
                list.add(x);
                swap.put(i, list);
            }
        }
    }

我的代碼唯一的區別是我沒有將數字5硬編碼到我的索引中; 我有一個方法,在原始的HashMap中找到最高的整數值並使用它。 我知道它工作正常,因為我得到相同的輸出,即使我在那里硬編碼5,我只是沒有包括它來節省空間。

我的目標是能夠使用任何數據集進行“反轉”,否則我只能對值進行硬編碼。 我從上面的代碼得到的輸出是這樣的:

swap = {1=[cat], 2=[boy], 3=[girl], 5=[human]}

正如您所看到的,我的問題是值ArrayList只保留放入其中的最后一個String,而不是收集所有String。 如何使ArrayList存儲每個String,而不僅僅是最后一個String?

使用Java 8,您可以執行以下操作:

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

map.put("cat", 1);
map.put("kid", 3);
map.put("girl", 3);
map.put("adult", 2);
map.put("human", 5);
map.put("dog", 2);
map.put("boy", 2);

Map<Integer, List<String>> newMap = map.keySet()
                                       .stream()
                                       .collect(Collectors.groupingBy(map::get));

System.out.println(newMap);

輸出將是:

{1=[cat], 2=[adult, dog, boy], 3=[kid, girl], 5=[human]}

你正在為每次迭代重新創建arrayList,我無法找到一種方法來使用該邏輯,這是一個很好的方法,但不需要檢查最大整數:

for (Map.Entry<String, Integer> entry : map.entrySet()) {
    String key = entry.getKey();
    Integer value = entry.getValue();
    List<String> get = swap.get(value);
    if (get == null) {
        get = new ArrayList<>();
        swap.put(value, get);
    }
    get.add(key);
}

最好的方法是迭代原始地圖的密鑰集

此外,您必須確保列表存在於目標地圖中的任何鍵:

for (Map.Entry<String,Integer>  inputEntry : map.entrySet())
  swap.computeIfAbsent(inputEntry.getValue(),()->new ArrayList<>()).add(inputEntry.getKey());

這顯然不是最好的解決方案,但是通過交換內部和外部循環來解決問題的方法與下面所示相同。

    Map<String, Integer> map = new HashMap<String, Integer>();
    map.put("cat", 1);
    map.put("kid", 3);
    map.put("girl", 3);
    map.put("adult", 2);
    map.put("human", 5);
    map.put("dog", 2);
    map.put("boy", 2);

    HashMap<Integer, ArrayList<String>> swap = new HashMap<Integer, ArrayList<String>>();

    for (Integer value = 0; value <= 5; value++) {
        ArrayList<String> list = new ArrayList<String>();
        for (String key : map.keySet()) {
            if (map.get(key) == value) {
                list.add(key);
            }
        }
        if (map.containsValue(value)) {
            swap.put(value, list);
        }
    }

產量

{1 = [貓],2 = [成人,狗,男孩],3 = [孩子,女孩],5 = [人類]}

我能想到的最好的辦法是使用Map.forEach法現有的地圖和Map.computeIfAbsent新地圖的方法:

Map<Integer, List<String>> swap = new HashMap<>();
map.forEach((k, v) -> swap.computeIfAbsent(v, k -> new ArrayList<>()).add(k));

作為旁注,您可以使用菱形運算符<>來創建新映射(在調用映射的構造函數時,不需要重復鍵和值的類型,因為編譯器會推斷它們)。

作為第二個附注,最好使用接口類型而不是具體類型,包括通用參數類型和實際類型。 這就是我分別使用ListMap而不是ArrayListHashMap

使用groupingBy雅各布的答案中,但使用Map.entrySet以獲得更好的性能,正如Boris建議的那樣

// import static java.util.stream.Collectors.*

Map<Integer, List<String>> swap = map.entrySet()
    .stream()
    .collect(groupingBy(Entry::getValue, mapping(Entry::getKey, toList())));

這使用了另外兩種Collectors方法: mappingtoList

如果不是這兩個輔助函數,解決方案可能如下所示:

Map<Integer, List<String>> swap = map.entrySet()
    .stream()
    .collect(
        groupingBy(
            Entry::getValue,
            Collector.of(
                ArrayList::new,
                (list, e) -> {
                    list.add(e.getKey());
                },
                (left, right) -> { // only needed for parallel streams
                    left.addAll(right);
                    return left;
                }
            )
        )
    );

或者,使用toMap而不是groupingBy

Map<Integer, List<String>> swap = map.entrySet()
    .stream()
    .collect(
        toMap(
            Entry::getValue,
            (e) -> new ArrayList<>(Arrays.asList(e.getKey())),
            (left, right) -> {
                left.addAll(right);
                return left;
            }
        )
    );

它接縫你覆蓋將它們添加到已經褶皺的arraylist的值instrad。 試試這個:

HashMap<Integer, ArrayList<String>> swapedMap = new HashMap<Integer, ArrayList<String>>();
for (String key : map.keySet()) {
    Integer swappedKey = map.get(key);

    ArrayList<String> a = swapedMap.get(swappedKey);
    if (a == null) {
        a = new ArrayList<String>();
        swapedMap.put(swappedKey, a)
    }

    a.add(key);
}

我沒有時間運行它(抱歉,現在沒有Java編譯器),但應該差不多好:)

您可以在Map中使用java-8中的新merge方法:

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

    map.forEach((key, value) -> {
        List<String> values = new ArrayList<>();
        values.add(key);
        newMap.merge(value, values, (left, right) -> {
            left.addAll(right);
            return left;
        });
    });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM