JAVA HashMap 2D,无法得到正确的方法来创建一个2D HashMap,我是指在另一个HashMap中创建一个HashMap。

4
我希望制作一个学生姓名和科目的板子,每个学生在每个科目上都有一个等级(或者没有……他可以放弃考试不写,那么他的情况就会是空的)。我想只使用HashMap。我的意思是,它将是这样的:
HashMap<String,HashMap<String,String>> bigBoard = 
    new HashMap<String,HashMap<String,String>>();

但我认为我没有正确的想法,因为对于每个学科,都会有许多分数(值),所以这是不可能的。我需要为每个学生制作一个地图吗?在他的学科中?但输出的表格将无法排列。你有什么建议吗?

例如,我想要一个类似于以下样式的表格。

Column-Key →
  Rowkey↓      Mathematics         Physics       Finance

Daniel Dolter         1.3           3.7 

Micky Mouse                                      5

Minnie Mouse                        1.7          n/a

Dagobert Duck         4.0                        1.0

我建议将所有的键和值都作为字符串使用,这样会更简单。

在实现我们的类之后(例如,类名为String2D),我们应该像这样使用它。

public static void main(String[] args) {

    String2D map2D = new String2D(); 
    map2D.put("Daniel Doster", "Practical Mathematics", "1.3"); 
    map2D.put("Daniel Doster", "IT Systeme", "3.7"); 
    map2D.put("Micky Mouse", "Finance", "5");
    map2D.put("Minnie Mouse", "IT Systeme", "1.7");
    map2D.put("Minnie Mouse", "Finance", "n/a");
    map2D.put("Dagobert Duck", "Practical Mathematics", "4.0");
    map2D.put("Dagobert Duck", "Finance", "1.0");
    System.out.println(map2D); 
} 

将不会出现"HashMap",也不允许使用Arrays。


1
你的解决方案对于作业或玩具应用程序来说应该可以正常工作,但如果你想实现一个真正的应用程序,可以查看其他答案。特别是使用嵌套哈希映射并不真正遵循面向对象编程的原则。 - Victor P.
4个回答

8
你可以使用这个类:
public class BiHashMap<K1, K2, V> {

private final Map<K1, Map<K2, V>> mMap;

public BiHashMap() {
    mMap = new HashMap<K1, Map<K2, V>>();
}

/**
 * Associates the specified value with the specified keys in this map (optional operation). If the map previously
 * contained a mapping for the key, the old value is replaced by the specified value.
 * 
 * @param key1
 *            the first key
 * @param key2
 *            the second key
 * @param value
 *            the value to be set
 * @return the value previously associated with (key1,key2), or <code>null</code> if none
 * @see Map#put(Object, Object)
 */
public V put(K1 key1, K2 key2, V value) {
    Map<K2, V> map;
    if (mMap.containsKey(key1)) {
        map = mMap.get(key1);
    } else {
        map = new HashMap<K2, V>();
        mMap.put(key1, map);
    }

    return map.put(key2, value);
}

/**
 * Returns the value to which the specified key is mapped, or <code>null</code> if this map contains no mapping for
 * the key.
 * 
 * @param key1
 *            the first key whose associated value is to be returned
 * @param key2
 *            the second key whose associated value is to be returned
 * @return the value to which the specified key is mapped, or <code>null</code> if this map contains no mapping for
 *         the key
 * @see Map#get(Object)
 */
public V get(K1 key1, K2 key2) {
    if (mMap.containsKey(key1)) {
        return mMap.get(key1).get(key2);
    } else {
        return null;
    }
}

/**
 * Returns <code>true</code> if this map contains a mapping for the specified key
 * 
 * @param key1
 *            the first key whose presence in this map is to be tested
 * @param key2
 *            the second key whose presence in this map is to be tested
 * @return Returns true if this map contains a mapping for the specified key
 * @see Map#containsKey(Object)
 */
public boolean containsKeys(K1 key1, K2 key2) {
    return mMap.containsKey(key1) && mMap.get(key1).containsKey(key2);
}

public void clear() {
    mMap.clear();
}

}

然后像这样创建并使用它:
BiHashMap<String,String,String> bigBoard = new BiHashMap<String,String,String>();

然而,为了提高性能,您可能希望将不同的成绩存储在一个数组中(假设您有一组固定的课程)。


谢谢Victor!但是我不被允许在我的类中使用任何数组。我必须实现那个类... :S 它必须只是类中的HashMaps。所以我需要“也许”实现BiHashMap... :-) - ZelelB
@ZelelB 我认为我给你的代码正是你所需要的 String2D,只需将 K1K2V 替换为 String 即可。如果是这种情况,请选择我的答案。 - Victor P.

0

您可以使用Google Guava的Table<R,C,V>集合。 它类似于eabraham的答案。 值V由行R和列C键入。 它是使用HashMap<R,HashMap<C,V>>的更好选择,后者很快变得难以阅读和处理。

有关更多信息,请参见他们的GitHub Wiki


0

我不认为嵌套的哈希映射是正确的方法。创建一个Student类和一个Subject类。

public class Student{
    private ArrayList<Subject> SubjectList = new ArrayList<Subject>();
    private String name;

    public Student(String name){
        this.name=name;
    }
    public void addSubject(Subject s){
        SubjectList.add(s);
    }
    public String getName(){
        return this.name;
    }
    //...add methods for other operations
}
public class Subject{
    private ArrayList<double > GradeList = new ArrayList<double>();
    private String name;

    public Subject(String name){
        this.name=name;
    }
    public void addGrade(double s){
        GradeList.add(s);
    }
    //...add methods for other operations
}

接下来,您可以将学生实例存储在哈希映射中。

public static void main(String[] args){
    HashMap<Students> hm = new HashMap<Students>();
    Student s = new Student("Daniel Dolter");
    Subject sub = new Subject("Mathematics");
    sub.addGrades(1.3);
    s.addSubject(sub);
    hm.put(s.getName(),s);
}

这也将是我的选择,尽管在科目列表中没有简单的方法查找特定科目所获得的成绩。 - Victor P.
你可以添加一个公共的double[] getGrades(String subjectName)方法来帮助实现这个功能。 - eabraham
谢谢大家的回答。但我需要在一个类中完成所有事情,并仅使用HashMaps..您可以在此处查看testclasspublic static void main(final String... ignored) { final StringMap2D map2D = new TrueStringMap2D(); map2D.put("Daniel Doster", "Practical Mathematics", "1.3"); map2D.put("Daniel Doster", "IT Systeme", "3.7"); map2D.put("Mike Muse", "Finance", "5"); map2D.put("Mine Muse", "Finance", "n/a"); map2D.put("Dago Dichie", "Practical Mathematics", "4.0"); map2D.put("Dago Dichie", "Finance", "1.0"); System.out.println(map2D); } - ZelelB
实现了我的StingMap2D(我必须实现的用于获取2D HashMap的类)后,在测试我的类之前,要编写main方法。它应该像这样工作……然后,通过打印输出,我应该能够得到你在第一篇帖子中看到的棋盘。 - ZelelB
阅读我的回答,我告诉你不要使用嵌套哈希映射。这不是标准做法,你最好使用像我描述的数据模型。 - eabraham
显示剩余2条评论

0
使用Java 8,可以使用computeIfAbsent在为空时插入默认值。因此,你可以将其作为2D地图的类型使用。
Map<RowType, Map<ColumnType, ValueType>> map = new WhateverMap<>();

假设所有类型都是int:

int get(int x, int y) 
  return map.computeIfAbsent(x, (key)->new WhateverMap<>()).computeIfAbsent(y,(key)->0);
}

void put(int x, int y, int value) 
  return map.computeIfAbsent(x, (key)->new WhateverMap<>()).put(y,value);
}

注意,这不是原子操作。因此,即使WhateverMap是线程安全的,但这并不意味着它是线程安全的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接