Реализация карты с использованием дубликатов ключей

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

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

Может быть, что-то в коллекциях или коллекциях google?

Ответ 1

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

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

Ответ 2

Нам не нужно зависеть от внешней библиотеки 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);
}

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

Ответ 3

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;

Ответ 4

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

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

Ответ 5

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

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)
{
   ...
}

Ответ 6

commons.apache.org

MultiValueMap class

Ответ 7

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

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

Реализация/изменение этого в вашей реализации может быть раздражающим.

В Guava это так же просто, как:

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

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

Ответ 8

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

Ответ 9

У меня был немного другой вариант этой проблемы: требовалось связать два разных значения с одним и тем же ключом. Просто разместив его здесь, если он поможет другим, я ввел значение 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 );
        }
}

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

Ответ 10

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;
        }
    }

Ответ 11

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

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

Ответ 12

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

Ответ 13

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

Например, в 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

Ответ 14

С небольшим взломом вы можете использовать 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);
    }
}

Ответ 15

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

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