Вопрос

Я хочу иметь карту с дубликатами ключей.

Я знаю, что существует множество реализаций map (Eclipse показывает мне около 50), поэтому держу пари, что должна быть такая, которая позволяет это.Я знаю, что легко написать свою собственную карту, которая делает это, но я бы предпочел использовать какое-нибудь существующее решение.

Может быть, что-нибудь в commons-collections или google-collections?

Это было полезно?

Решение

Вы ищете multimap, и действительно, как commons-collections, так и Guava имеют несколько реализаций для этого.Мультикарты позволяют использовать несколько ключей, поддерживая набор значений для каждого ключа, т.е.вы можете поместить на карту один объект, но при этом вы получаете коллекцию.

Если вы можете использовать Java 5, я бы предпочел Guava Multimap поскольку это ориентировано на дженерики.

Другие советы

Нам не нужно зависеть от внешней библиотеки Google Collections.Вы можете просто реализовать следующую карту:

Map<String, ArrayList<String>> hashMap = new HashMap<String, ArrayList>();

public static void main(String... arg) {
   // Add data with duplicate keys
   addValues("A", "a1");
   addValues("A", "a2");
   addValues("B", "b");
   // View data.
   Iterator it = hashMap.keySet().iterator();
   ArrayList tempList = null;

   while (it.hasNext()) {
      String key = it.next().toString();             
      tempList = hashMap.get(key);
      if (tempList != null) {
         for (String value: tempList) {
            System.out.println("Key : "+key+ " , Value : "+value);
         }
      }
   }
}

private void addValues(String key, String value) {
   ArrayList tempList = null;
   if (hashMap.containsKey(key)) {
      tempList = hashMap.get(key);
      if(tempList == null)
         tempList = new ArrayList();
      tempList.add(value);  
   } else {
      tempList = new ArrayList();
      tempList.add(value);               
   }
   hashMap.put(key,tempList);
}

Пожалуйста, не забудьте точно настроить код.

Multimap<Integer, String> multimap = ArrayListMultimap.create();

multimap.put(1, "A");
multimap.put(1, "B");
multimap.put(1, "C");
multimap.put(1, "A");

multimap.put(2, "A");
multimap.put(2, "B");
multimap.put(2, "C");

multimap.put(3, "A");

System.out.println(multimap.get(1));
System.out.println(multimap.get(2));       
System.out.println(multimap.get(3));

Результат равен:

[A,B,C,A]
[A,B,C]
[A]

Примечание: нам нужно импортировать файлы библиотеки.

http://www.java2s.com/Code/Jar/g/Downloadgooglecollectionsjar.htm

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;

или https://commons.apache.org/proper/commons-collections/download_collections.cgi

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;

Вы могли бы просто передать массив значений для значения в обычной хэш-карте, имитируя таким образом дублирующиеся ключи, и вам решать, какие данные использовать.

Вы также можете просто использовать Мультикарточка, хотя мне самому не нравится идея дубликатов ключей.

Если вы хотите выполнить итерацию по списку пар ключ-значение (как вы написали в комментарии), то список или массив должны быть лучше.Сначала объедините ваши ключи и значения:

public class Pair
{
   public Class1 key;
   public Class2 value;

   public Pair(Class1 key, Class2 value)
   {
      this.key = key;
      this.value = value;
   }

}

Замените Class1 и Class2 типами, которые вы хотите использовать для ключей и значений.

Теперь вы можете поместить их в массив или список и выполнять итерации по ним:

Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
   ...
}
commons.apache.org

MultiValueMap class

Эта проблема может быть решена с помощью списка элементов карты List<Map.Entry<K,V>>.Нам не нужно использовать ни внешние библиотеки, ни новую реализацию Map.Запись на карте может быть создана следующим образом: Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);

Учитесь на моих ошибках...пожалуйста, не внедряйте это самостоятельно.Мультикарта гуавы - это правильный путь.

Общим улучшением, необходимым в multimaps, является запрет дублирования пар ключи-значение.

Внедрение / изменение этого в вашей реализации может раздражать.

В Гуаве это так же просто, как:

HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();

ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();

У меня был немного другой вариант этого вопроса:Требовалось связать два разных значения с одним и тем же ключом.Просто разместив это здесь на случай, если это поможет другим, я ввел HashMap в качестве значения:

/* @param frameTypeHash: Key -> Integer (frameID), Value -> HashMap (innerMap)
   @param innerMap: Key -> String (extIP), Value -> String
   If the key exists, retrieve the stored HashMap innerMap 
   and put the constructed key, value pair
*/
  if (frameTypeHash.containsKey(frameID)){
            //Key exists, add the key/value to innerHashMap
            HashMap innerMap = (HashMap)frameTypeHash.get(frameID);
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);

        } else {
            HashMap<String, String> innerMap = new HashMap<String, String>();
            innerMap.put(extIP, connName+":"+frameType+":"+interfaceName);
            // This means the key doesn't exists, adding it for the first time
            frameTypeHash.put(frameID, innerMap );
        }
}

В приведенном выше коде ключ frameId считывается из первой строки входного файла в каждой строке, значение для frameTypeHash создается путем разделения оставшейся строки и изначально сохранялось как объект String, с течением времени файл начал содержать несколько строк (с разными значениями), связанных с одним и тем же ключом frameId, поэтому frameTypeHash был перезаписан последней строкой в качестве значения.Я заменил объект String другим объектом HashMap в качестве поля value, это помогло сохранить один ключ для сопоставления разных значений.

class  DuplicateMap<K, V> 
{
    enum MapType
    {
        Hash,LinkedHash
    }

    int HashCode = 0;
    Map<Key<K>,V> map = null;

    DuplicateMap()
    {
        map = new HashMap<Key<K>,V>();
    }

    DuplicateMap( MapType maptype )
    {
        if ( maptype == MapType.Hash ) {
            map = new HashMap<Key<K>,V>();
        }
        else if ( maptype == MapType.LinkedHash ) {
            map = new LinkedHashMap<Key<K>,V>();
        }
        else
            map = new HashMap<Key<K>,V>();
    }

    V put( K key, V value  )
    {

        return map.put( new Key<K>( key , HashCode++ ), value );
    }

    void putAll( Map<K, V> map1 )
    {
        Map<Key<K>,V> map2 = new LinkedHashMap<Key<K>,V>();

        for ( Entry<K, V> entry : map1.entrySet() ) {
            map2.put( new Key<K>( entry.getKey() , HashCode++ ), entry.getValue());
        }
        map.putAll(map2);
    }

    Set<Entry<K, V>> entrySet()
    {
        Set<Entry<K, V>> entry = new LinkedHashSet<Map.Entry<K,V>>();
        for ( final Entry<Key<K>, V> entry1 : map.entrySet() ) {
            entry.add( new Entry<K, V>(){
                private K Key = entry1.getKey().Key();
                private V Value = entry1.getValue();

                @Override
                public K getKey() {
                    return Key;
                }

                @Override
                public V getValue() {
                    return Value;
                }

                @Override
                public V setValue(V value) {
                    return null;
                }});
        }

        return entry;
    }

    @Override
    public String toString() {
        StringBuilder builder = new  StringBuilder();
        builder.append("{");
        boolean FirstIteration = true;
        for ( Entry<K, V> entry : entrySet() ) {
            builder.append( ( (FirstIteration)? "" : "," ) + ((entry.getKey()==null) ? null :entry.getKey().toString() ) + "=" + ((entry.getValue()==null) ? null :entry.getValue().toString() )  );
            FirstIteration = false;
        }
        builder.append("}");
        return builder.toString();
    }

    class Key<K1>
    {
        K1 Key;
        int HashCode;

        public Key(K1 key, int hashCode) {
            super();
            Key = key;
            HashCode = hashCode;
        }

        public K1 Key() {
            return Key;
        }

        @Override
        public String toString() {
            return  Key.toString() ;
        }

        @Override
        public int hashCode() {

            return HashCode;
        }
    }

Не могли бы вы также объяснить контекст, для которого вы пытаетесь реализовать карту с дублирующимися ключами?Я уверен, что могло бы быть лучшее решение.Карты предназначены для хранения уникальных ключей по уважительной причине.Хотя, если бы ты действительно хотел это сделать;вы всегда можете расширить класс, написав простой пользовательский класс map, который имеет функцию предотвращения столкновений и позволит вам хранить несколько записей с одинаковыми ключами.

Примечание:Вы должны реализовать функцию предотвращения столкновений таким образом, чтобы сталкивающиеся ключи преобразовывались в уникальный набор "всегда".Что-то простое, например, добавление ключа к хэш-коду объекта или что-то в этом роде?

для полноты картины в Apache Commons Collections также есть Мультикарточка.Недостатком, конечно, является то, что Apache Commons не использует дженерики.

С небольшим взломом вы можете использовать HashSet с дубликатами ключей.ПРЕДУПРЕЖДЕНИЕ:это сильно зависит от реализации HashSet.

class MultiKeyPair {
    Object key;
    Object value;

    public MultiKeyPair(Object key, Object value) {
        this.key = key;
        this.value = value;
    }

    @Override
    public int hashCode() {
        return key.hashCode();
    }
}

class MultiKeyList extends MultiKeyPair {
    ArrayList<MultiKeyPair> list = new ArrayList<MultiKeyPair>();

    public MultiKeyList(Object key) {
        super(key, null);
    }

    @Override
    public boolean equals(Object obj) {
        list.add((MultiKeyPair) obj);
        return false;
    }
}

public static void main(String[] args) {
    HashSet<MultiKeyPair> set = new HashSet<MultiKeyPair>();
    set.add(new MultiKeyPair("A","a1"));
    set.add(new MultiKeyPair("A","a2"));
    set.add(new MultiKeyPair("B","b1"));
    set.add(new MultiKeyPair("A","a3"));

    MultiKeyList o = new MultiKeyList("A");
    set.contains(o);

    for (MultiKeyPair pair : o.list) {
        System.out.println(pair.value);
    }
}

Если имеются дубликаты ключей, то ключ может соответствовать более чем одному значению.Очевидным решением является сопоставление ключа со списком этих значений.

Например, в Python:

map = dict()
map["driver"] = list()
map["driver"].append("john")
map["driver"].append("mike")
print map["driver"]          # It shows john and mike
print map["driver"][0]       # It shows john
print map["driver"][1]       # It shows mike

Я использовал это:

java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();

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

это подробное решение имеет множество недостатков и подвержено ошибкам.IT подразумевает, что нам нужно создать экземпляр коллекции для каждого значения, проверить ее наличие перед добавлением или удалением значения, удалить ее вручную, когда не останется значений, и так далее.

2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface 

java-карта-дубликаты-ключей

как насчет такой реализации MultiMap?

public class MultiMap<K, V> extends HashMap<K, Set<V>> {
  private static final long serialVersionUID = 1L;
  private Map<K, Set<V>> innerMap = new HashMap<>();

  public Set<V> put(K key, V value) {
    Set<V> valuesOld = this.innerMap.get(key);
    HashSet<V> valuesNewTotal = new HashSet<>();
    if (valuesOld != null) {
      valuesNewTotal.addAll(valuesOld);
    }
    valuesNewTotal.add(value);
    this.innerMap.put(key, valuesNewTotal);
    return valuesOld;
  }

  public void putAll(K key, Set<V> values) {
    for (V value : values) {
      put(key, value);
    }
  }

  @Override
  public Set<V> put(K key, Set<V> value) {
    Set<V> valuesOld = this.innerMap.get(key);
    putAll(key, value);
    return valuesOld;
  }

  @Override
  public void putAll(Map<? extends K, ? extends Set<V>> mapOfValues) {
    for (Map.Entry<? extends K, ? extends Set<V>> valueEntry : mapOfValues.entrySet()) {
      K key = valueEntry.getKey();
      Set<V> value = valueEntry.getValue();
      putAll(key, value);
    }
  }

  @Override
  public Set<V> putIfAbsent(K key, Set<V> value) {
    Set<V> valueOld = this.innerMap.get(key);
    if (valueOld == null) {
      putAll(key, value);
    }
    return valueOld;
  }

  @Override
  public Set<V> get(Object key) {
    return this.innerMap.get(key);
  }

  @Override
  etc. etc. override all public methods size(), clear() .....

}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top