LinkedHashMap存重复键后如何保留插入顺序并允许重复键?
实现保留插入顺序且允许重复键的"Map"结构
嘿,这个需求太常见啦——想要像LinkedHashMap那样记住键值对的插入顺序,但又不想让重复的键覆盖掉之前的值对吧?我给你几个实用的解决方案,你可以根据自己的场景来选:
方案1:基于LinkedHashMap封装多值Map
最直接的思路是把LinkedHashMap的值类型改成列表,每次插入时,如果键已经存在,就把新值追加到对应的列表里;如果不存在,就新建一个列表存放值。我们可以把这个逻辑封装成一个工具类,用起来和普通Map差不多:
import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.AbstractMap.SimpleEntry; public class OrderedMultiMap<K, V> { // 用LinkedHashMap保证键的插入顺序 private final LinkedHashMap<K, List<V>> innerMap = new LinkedHashMap<>(); // 自定义put方法:不覆盖,只追加 public void put(K key, V value) { // computeIfAbsent会自动处理键不存在的情况,新建列表 innerMap.computeIfAbsent(key, k -> new ArrayList<>()).add(value); } // 获取某个键对应的所有值 public List<V> get(K key) { return innerMap.getOrDefault(key, Collections.emptyList()); } // 获取所有按插入顺序排列的键值对(包括重复键) public List<Map.Entry<K, V>> getAllEntries() { List<Map.Entry<K, V>> entries = new ArrayList<>(); for (Map.Entry<K, List<V>> entry : innerMap.entrySet()) { K key = entry.getKey(); for (V value : entry.getValue()) { entries.add(new SimpleEntry<>(key, value)); } } return entries; } // 可选:添加其他常用方法,比如获取大小、清空等 public int size() { return innerMap.values().stream().mapToInt(List::size).sum(); } public void clear() { innerMap.clear(); } }
用法示例
把你原来的代码改成这样就行:
OrderedMultiMap<String, Object> myMap = new OrderedMultiMap<>(); myMap.put("a", list1); myMap.put("e", list2); myMap.put("i", list3); myMap.put("o", list4); myMap.put("u", list5); myMap.put("g", list6); myMap.put("a", list7); // 遍历所有条目,会按插入顺序输出:a->list1, e->list2, ..., a->list7 for (Map.Entry<String, Object> entry : myMap.getAllEntries()) { System.out.println(entry.getKey() + " -> " + entry.getValue()); }
方案2:维护独立条目列表的自定义Map
如果需要更细粒度的控制(比如按插入索引获取某个键值对,或者明确区分每一次插入操作),可以同时维护一个条目列表和一个索引Map:
import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.AbstractMap.SimpleEntry; import java.util.stream.Collectors; public class OrderedDuplicateMap<K, V> { // 用LinkedList保存所有插入的条目,保证顺序 private final LinkedList<Map.Entry<K, V>> entryList = new LinkedList<>(); // 用LinkedHashMap快速查找某个键对应的所有条目 private final LinkedHashMap<K, List<Map.Entry<K, V>>> keyIndex = new LinkedHashMap<>(); public void put(K key, V value) { Map.Entry<K, V> newEntry = new SimpleEntry<>(key, value); entryList.add(newEntry); keyIndex.computeIfAbsent(key, k -> new ArrayList<>()).add(newEntry); } // 获取所有按插入顺序排列的条目 public List<Map.Entry<K, V>> getAllEntries() { return new ArrayList<>(entryList); } // 获取某个键对应的所有值 public List<V> getValues(K key) { List<Map.Entry<K, V>> entries = keyIndex.get(key); if (entries == null) { return List.of(); } return entries.stream().map(Map.Entry::getValue).collect(Collectors.toList()); } // 根据插入索引获取条目 public Map.Entry<K, V> getEntryByIndex(int index) { return entryList.get(index); } public int size() { return entryList.size(); } }
这个方案的好处是,每个插入的键值对都是独立的条目,你可以直接通过索引访问某一次插入的内容,适合需要精确跟踪每一步操作的场景。
可选:用第三方库快速实现
如果项目里已经引入了Guava库,那直接用LinkedHashMultimap就可以了——它天生支持保留插入顺序和重复键,用法超级简单:
import com.google.common.collect.LinkedHashMultimap; public class Demo { public static void main(String[] args) { LinkedHashMultimap<String, Object> multimap = LinkedHashMultimap.create(); multimap.put("a", list1); multimap.put("e", list2); multimap.put("a", list7); // 遍历的时候会严格按插入顺序输出所有键值对 for (Map.Entry<String, Object> entry : multimap.entries()) { System.out.println(entry.getKey() + " -> " + entry.getValue()); } } }
以上几种方案都能满足你的需求,选最适合你项目情况的就行~
内容的提问来源于stack exchange,提问作者Nain
相关产品推荐
相关产品推荐

