我应该使用Java中的哪种数据结构以有序的形式存储键值对?无多重记录
我正在从事一个项目,我需要以有序的方式存储键值对(一对一映射)。然后我应该能够使用值检索键,使用键检索值。我看过地图、集合和哈希表,但它们不是有序的 另外,虽然很简单,但如果我们能够同时检索键和值,也就是说,接口支持这样的函数,那就太好了我应该使用Java中的哪种数据结构以有序的形式存储键值对?无多重记录,java,data-structures,key-value,Java,Data Structures,Key Value,我正在从事一个项目,我需要以有序的方式存储键值对(一对一映射)。然后我应该能够使用值检索键,使用键检索值。我看过地图、集合和哈希表,但它们不是有序的 另外,虽然很简单,但如果我们能够同时检索键和值,也就是说,接口支持这样的函数,那就太好了 编辑:键和值都是唯一的。维护插入的订单就足够了。应该适合您。通读链接应该适合您。通读链接您将需要两个LinkedHashMap。您可以创建内部使用两个LinkedHashMap的自定义类。一个用于将键映射到值,另一个用于将值映射到键。您将需要两个LinkedH
编辑:键和值都是唯一的。维护插入的订单就足够了。应该适合您。通读链接应该适合您。通读链接您将需要两个
LinkedHashMap
。您可以创建内部使用两个LinkedHashMap
的自定义类。一个用于将键映射到值,另一个用于将值映射到键。您将需要两个LinkedHashMap
。您可以创建内部使用两个LinkedHashMap
的自定义类。一个用于将键映射到值,另一个用于将值映射到键。请注意,您没有定义什么是“有序的”。A允许按插入顺序对键(以及值)进行迭代。相反,a允许您使用比较器指定排序顺序,并确保添加到映射的所有项目都按排序顺序存储。100次中有99次,其中一个课程应该就是你所需要的。或者,谷歌的项目有几个非常好的实现,你可能会发现它们适合你的需要
我强烈警告您:如果您认为您需要的内容超出了这些课程所能提供的内容,那么您可能过度设计了您的问题。
出于无法完全证明的原因,我为您实现了一个合适的
UniqueOrderedBiMap
,它与Java集合框架兼容,并且所有实现的函数都能高效运行。您可以使用任何您认为合适的底层映射(如果您真的需要,包括一个未排序的映射),并且键和值总是唯一的。请注意,LinkedHashMap
是一个非常薄的包装,因为这就是您所需要的,LinkedHashMap
带有额外检查以确保值保持唯一性
出于好奇,请检查UniqueOrderedMap
的此答案修订历史,该地图缺少getKey()
和removeKey()
方法,但更正确地实现了Map
接口,只需要一个HashSet而不是HashMap来存储已知值
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class UniqueOrderedBiMap<K, V>implements Map<K, V> {
private Map<K, V> orderedMap;
private HashMap<V, K> valueMap;
public UniqueOrderedBiMap() {
this(new LinkedHashMap<K,V>());
}
public UniqueOrderedBiMap(Map<K, V> underlyingMap) {
orderedMap = underlyingMap;
valueMap = new HashMap<V, K>(orderedMap.size());
for(Map.Entry<K, V> e : orderedMap.entrySet()) {
if(!valueMap.containsKey(e.getValue())) { // Duplicate value
// could instead fail softly by removing the associated item from the map, but this seems cleaner/clearer.
// generally this constructor should be passed an empty map anyways
throw new IllegalArgumentException("Duplicate value "+e.getValue()+" found in underlying map.");
}
valueMap.put(e.getValue(), e.getKey());
}
}
@Override
public int size() {
return orderedMap.size();
}
@Override
public boolean isEmpty() {
return orderedMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return orderedMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
// more efficient than iterating over the map
return valueMap.containsKey(value);
}
@Override
public V get(Object key) {
return orderedMap.get(key);
}
public K getKey(V value) {
return valueMap.get(value);
}
// Likely want to implement a forcePut(K, V) method like Guava's BiMaps do
@Override
public V put(K key, V value) {
if(valueMap.containsKey(value)) {
throw new IllegalArgumentException("Cannot insert non-unique value "+value);
}
V ret = orderedMap.put(key, value);
valueMap.remove(ret);
valueMap.put(value, key);
return ret;
}
@Override
public V remove(Object key) {
V ret = orderedMap.remove(key);
valueMap.remove(ret);
return ret;
}
public K removeKey(V value) {
K ret = valueMap.remove(value);
orderedMap.remove(ret);
return ret;
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
// Existing Map implementation's putAll have some optimizations we
// could take advantage of, but this isn't unreasonable for a first pass
for(Entry<? extends K, ? extends V> e : m.entrySet()) {
put(e.getKey(), e.getValue());
}
}
@Override
public void clear() {
orderedMap.clear();
valueMap.clear();
}
@Override
public Set<K> keySet() {
return orderedMap.keySet();
}
@Override
public Collection<V> values() {
return orderedMap.values();
}
@Override
public Set<java.util.Map.Entry<K, V>> entrySet() {
return orderedMap.entrySet();
}
@Override
public boolean equals(Object o) {
if(o instanceof UniqueOrderedBiMap) {
UniqueOrderedBiMap<?,?> map = (UniqueOrderedBiMap<?,?>)o;
return orderedMap.equals(map.orderedMap);
}
return false;
}
@Override
public int hashCode() {
return orderedMap.hashCode();
}
@Override public String toString() {
return orderedMap.toString();
}
public static void main(String[] args) {
String[] names = { "Marcus", "Jim", "Tom", "Sam" };
String[] grades = { "A", "B", "D", "F" };
UniqueOrderedBiMap<String,String> insertionMap = new UniqueOrderedBiMap<>();
UniqueOrderedBiMap<String,String> sortedMap = new UniqueOrderedBiMap<>(new TreeMap<String,String>());
for(int i = 0; i < names.length; i++) {
insertionMap.put(names[i], grades[i]);
sortedMap.put(names[i], grades[i]);
}
// Poor man's assert
System.out.println(insertionMap.toString().equals("{Marcus=A, Jim=B, Tom=D, Sam=F}"));
System.out.println(sortedMap.toString().equals("{Jim=B, Marcus=A, Sam=F, Tom=D}"));
insertionMap.put("Tom", "C");
sortedMap.put("Tom", "C");
System.out.println(insertionMap.toString().equals("{Marcus=A, Jim=B, Tom=C, Sam=F}"));
System.out.println(sortedMap.toString().equals("{Jim=B, Marcus=A, Sam=F, Tom=C}"));
try {
insertionMap.put("Sam", "C");
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
try {
sortedMap.put("Sam", "C");
} catch (IllegalArgumentException e) {
System.out.println(e.getMessage());
}
insertionMap.remove("Tom");
sortedMap.remove("Tom");
insertionMap.put("Sam", "C");
sortedMap.put("Sam", "C");
System.out.println(insertionMap.toString().equals("{Marcus=A, Jim=B, Sam=C}"));
System.out.println(sortedMap.toString().equals("{Jim=B, Marcus=A, Sam=C}"));
insertionMap.removeKey("A");
sortedMap.removeKey("A");
System.out.println(insertionMap.toString().equals("{Jim=B, Sam=C}"));
System.out.println(sortedMap.toString().equals("{Jim=B, Sam=C}"));
}
}
import java.util.Collection;
导入java.util.HashMap;
导入java.util.LinkedHashMap;
导入java.util.Map;
导入java.util.Set;
导入java.util.TreeMap;
公共类UniqueOrderedBiMapiImplements映射{
私有地图有序地图;
私有HashMap-valueMap;
公共UniqueOrderedBiMap(){
此(新LinkedHashMap());
}
公共UniqueOrderedBiMap(地图下的地图){
orderedMap=参考地图;
valueMap=newhashmap(orderedMap.size());
对于(Map.Entry e:orderedMap.entrySet()){
如果(!valueMap.containsKey(e.getValue()){//重复值
//相反,可以通过从映射中删除相关项来柔和地失败,但这看起来更清晰。
//通常,无论如何都应该向该构造函数传递一个空映射
抛出新的IllegalArgumentException(“在基础映射中找到重复值”+e.getValue()+);
}
put(e.getValue(),e.getKey());
}
}
@凌驾
公共整数大小(){
return orderedMap.size();
}
@凌驾
公共布尔值为空(){
return orderedMap.isEmpty();
}
@凌驾
公共布尔containsKey(对象键){
返回orderedMap.containsKey(键);
}
@凌驾
公共布尔包含值(对象值){
//比在地图上迭代更有效
返回valueMap.containsKey(值);
}
@凌驾
public V get(对象键){
returnorderedmap.get(键);
}
公共K getKey(V值){
返回valueMap.get(值);
}
//可能想要实现一个forcePut(K,V)方法,就像Guava的BiMaps一样
@凌驾
公共V输入(K键,V值){
if(valueMap.containsKey(值)){
抛出新的IllegalArgumentException(“无法插入非唯一值”+值);
}
V ret=orderedMap.put(键,值);
valueMap.remove(ret);
valueMap.put(值、键);
返回ret;
}
@凌驾
公共V删除(对象密钥){
V ret=orderedMap.remove(键);
valueMap.remove(ret);
返回ret;
}
公共K removeKey(V值){
K ret=valueMap.remove(值);
orderedMap.remove(ret);
返回ret;
}
@凌驾
公共空间(地图)o;
返回orderedMap.equals(map.orderedMap);
}
返回false;
}
@凌驾
公共int hashCode(){
return orderedMap.hashCode();
}
@重写公共字符串toString(){
return orderedMap.toString();
}
公共静态void main(字符串[]args){
String[]name={“Marcus”、“Jim”、“Tom”、“Sam”};
字符串[]等级={“A”、“B”、“D”、“F”};
UniqueOrderedBiMap insertionMap=新的UniqueOrderedBiMap();
UniqueOrderedBiMap sortedMap=新的UniqueOrderedBiMap(新树映射());
for(int i=0;i