Java中的多对一映射

时间:2014-03-05 16:12:26

标签: java map hashmap mapping key-value

我正在尝试在java中构建多对一键值对。直到现在我所有的都是这个

  public class KeyStore {
    int i=1;
    Map<Integer,String> map1=new HashMap<Integer,String>();
    Map<String,List<Integer>> map2=new HashMap<String,List<Integer>>();

    public synchronized int put(String blobString) {
    if(map1.containsValue(blobString)){
    int r=blobString.hashCode()+i*blobString.hashCode();
    i++;
    map1.put(r, blobString);
    List<Integer> j=map2.get(blobString);
    List<Integer> k=j;
    map2.remove(blobString);
    k.add(r);
    map2.put(blobString, k);
    return r;

}
else{
    map1.put(blobString.hashCode(),blobString);
    List<Integer> x=new ArrayList<Integer>();
    x.add(blobString.hashCode());
    map2.put(blobString,x);
    return blobString.hashCode();
}
}

     public synchronized String get(int objectId) {
         return map1.get(objectId);
  }

如果我put

,这是做什么的
  ks.put("abc") 

  ks.put("abc")

这里ks是包含上述方法的类的瞬间。

导致

{1916062554=abc, 958031277=abc}

但我想要的是

191602554,958031277=abc

如果我对这些键中的任何一个使用get(),它应该输出值abc。此外,delete()应删除最新的密钥,而不会损害其他密钥。

我想过使用

Map<ArrayList<Integer>,String> keystore=new HashMap<ArrayListInteger>,String>();

但我不知道如何实现put方法,即如何在列表映射中插入键。需要帮助。

编辑1

我能够使get和put方法起作用。挣扎于删除方法。写了一些像这样的东西

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

public synchronized void delete(int objectId) {
  map1.remove(objectId);
  Iterator<Entry<String, List<Integer>>> it = map2.entrySet().iterator();
 loop1: while (it.hasNext()) {
        @SuppressWarnings("rawtypes")
        Map.Entry pairs = (Map.Entry)it.next();
        @SuppressWarnings("unchecked")
        List<Integer> z=(List<Integer>) pairs.getValue();
         if(z.contains(objectId)){
             //System.out.println(z.size());
             String key=(String) pairs.getKey();
             System.out.println(z+" "+key);
            if(z.size()==1){
                map2.remove(key);
                break loop1;
            }
            else{
                z.remove(objectId);
                map2.remove(key);
                map2.put(key, z);
                break loop1;
            }
        }
  }
  }

基本上map1包含映射

123=>abc,456=>abc

和map2包含

abc=>[123,456]

我收到了一个arrayindexoutofbound异常。我在删除方法中尝试的是迭代每个blob String,然后在所需的objectID存在时检查与blobstring关联的值列表。如果是,那么我从列表中删除该对象id并附加新映射。有什么帮助吗?

编辑2

上面给出了更新和工作的get和put方法。

2 个答案:

答案 0 :(得分:1)

Map JavaDoc说:

  

地图不能包含重复的键;每个键最多可以映射一个值。

但是你可以通过将值设为 list 字符串来解决这个问题:

   import  java.util.ArrayList;
   import  java.util.HashMap;
   import  java.util.Iterator;
   import  java.util.List;
   import  java.util.Map;
   import  java.util.Set;

/**
   <P>{@code java MultiValueHashMap}</P>
 **/
public class MultiValueHashMap  {
   public static final void main(String[] ignored)  {
      Map<Integer,List<String>> mapOfIntStrs = new HashMap<Integer,List<String>>();

      //Add elements
         addStringToMap(mapOfIntStrs, 1, "one");
         addStringToMap(mapOfIntStrs, 1, "two");
         addStringToMap(mapOfIntStrs, 1, "three");
         addStringToMap(mapOfIntStrs, 2, "four");
         addStringToMap(mapOfIntStrs, 2, "five");

      //Output 
         Set<Integer> keyNumSet = mapOfIntStrs.keySet();
         Iterator<Integer> keyNumItr = keyNumSet.iterator();
         while(keyNumItr.hasNext())  {
            Integer keyNum = keyNumItr.next();
            List<String> strList = mapOfIntStrs.get(keyNum);
            System.out.println(keyNum);
            for(String s : strList)  {
               System.out.println("  " + s);
            }
         }
   }
   private static final void addStringToMap(Map<Integer,List<String>> mapTo_addTo, int keyNum, String value)  {
      if(mapTo_addTo.containsKey(keyNum))  {
         mapTo_addTo.get(keyNum).add(value);
      }  else  {
         List<String> strList = new ArrayList<String>();
         strList.add(value);
         mapTo_addTo.put(keyNum, strList);
      }
   }

}

输出:

[C:\java_code\]java MultiValueHashMap
1
  one
  two
  three
2
  four
  five

关于每个值的多个键,你当然可以这样做,虽然我不确定它是否值得推荐。根据{{​​3}}:

  

HashMap类大致相当于Hashtable,除了它是不同步的并且允许空值。

HashMap API

  

要成功存储和检索哈希表中的对象,用作键的对象必须实现hashCode方法和equals方法。

因此虽然这适用于ArrayList<Integer>键,但对于包含非标准类的自定义键的任何内容,除非您正确地为这些对象实现hashCode(),否则HashMap可能不会功能正常。

答案 1 :(得分:1)

您的类中似乎需要一些数据结构作为字段:

  • stringMap:Map<Integer,String>
    • {1916062554=abc, 958031277=abc}
    • 因为get您希望按键
    • 查找项目
  • 键:Map<String,List<Integer>>
    • { "abc" = {1916062554, 958031277}
    • 因为delete您希望按顺序知道给定项目的键。

添加到地图:

 public void put(String item) {
     List<Integer> list = getOrCreateList(item,keys);
     int key = calculateKey(item,list);
     list.add(key);
     stringMap.put(key,item);
 }

 private static List<Integer> getOrCreateList(String item, Map<String,List<Integer>> map) {
     List<Integer> list = map.get(item);
     if(list == null) {
         list = new ArrayList<Integer>();
         map.put(item,list);
     }
     return list;
 }

从地图上获取很容易:

 public String get(int key) {
     return stringMap.get(key);
 }

要从地图中删除 - 如果我理解您的要求 - 您需要在列表中找到与提供的密钥相对应的最新密钥...

 public void delete(int key) {
     String item = stringMap.get(key);
     if(item == null) {
        // ... deal with
     }
     List<Integer> keys = keys.get(item);

     // lazily using methods which don't exist in the Java API
     // but which illustrate the point.
     keys.removeLast();
     if(keys.isEmpty()) {
         stringMap.remove(key);
         list.remove(item);
     }
 }