la mise en œuvre de la carte avec des clés en double
-
21-08-2019 - |
Question
Je veux avoir une carte avec des clés en double.
Je sais, donc je parie qu'il doit y avoir une, il y a de nombreuses implémentations de carte (Eclipse me montre environ 50) qui permet. Je sais qu'il est facile d'écrire votre propre carte qui fait cela, mais je préfère utiliser une solution existante.
Peut-être quelque chose dans commons-collections ou google-collections?
La solution
Vous recherchez un multimap, et même les deux communes-collections et goyave avez plusieurs implémentations pour cela. Multimaps permettent de multiples clés en maintenant une collection de valeurs par clé, à savoir que vous pouvez mettre un objet dans la carte, mais vous récupérez une collection.
Si vous pouvez utiliser Java 5, je préférerais de goyave Multimap
car il est générique SENSIBLE.
Autres conseils
Nous ne devons pas dépendre des collections Google bibliothèque externe. Vous pouvez simplement mettre en œuvre la carte suivante:
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);
}
S'il vous plaît assurez-vous d'affiner le code.
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));
sortie est la suivante:
[A,B,C,A]
[A,B,C]
[A]
Remarque: nous avons besoin de fichiers de bibliothèque importer
.http://www.java2s.com/Code/Jar/g/ Downloadgooglecollectionsjar.htm
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
ou https://commons.apache.org/proper/commons-collections /download_collections.cgi
import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;
Vous pouvez simplement passer un tableau de valeurs pour la valeur dans une HashMap régulière, simulant ainsi les clés en double, et il serait à vous de décider quelles sont les données à utiliser.
Vous pouvez aussi utiliser un MultiMap , bien que je n'aime pas l'idée de clés en double moi-même.
Si vous voulez itérer sur une liste de paires de valeurs-clés (comme vous avez écrit dans le commentaire), puis une liste ou un tableau devrait être mieux. Tout d'abord combiner vos clés et valeurs:
public class Pair
{
public Class1 key;
public Class2 value;
public Pair(Class1 key, Class2 value)
{
this.key = key;
this.value = value;
}
}
Remplacer et Class1 Classe2 avec les types que vous souhaitez utiliser pour les clés et les valeurs.
Maintenant, vous pouvez les mettre dans un tableau ou une liste et itérer sur eux:
Pair[] pairs = new Pair[10];
...
for (Pair pair : pairs)
{
...
}
commons.apache.org
MultiValueMap class
Ce problème peut être résolu avec une liste d'entrée de List<Map.Entry<K,V>>
carte. Nous ne devons pas utiliser ni bibliothèques externes ni nouvelle implémentation de Map. Une entrée de la carte peut être créé comme ceci:
Map.Entry<String, Integer> entry = new AbstractMap.SimpleEntry<String, Integer>("key", 1);
En savoir de mes erreurs ... s'il vous plaît ne pas mettre en œuvre sur votre propre. Goyave multimap est le chemin à parcourir.
Une amélioration commune requise dans multimaps est d'interdire les paires dupliquées touches de valeur.
La mise en œuvre / changer cela dans une implémentation peut être gênant.
Dans Goyave est aussi simple que:
HashMultimap<String, Integer> no_dupe_key_plus_val = HashMultimap.create();
ArrayListMultimap<String, Integer> allow_dupe_key_plus_val = ArrayListMultimap.create();
J'ai eu une variante légèrement différente de cette question: Il est nécessaire d'associer deux valeurs différentes avec la même clé. affichage juste ici dans le cas où il aide les autres, je vous ai présenté un HashMap comme la valeur:
/* @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 );
}
}
Dans le code au-dessus du frameID clé est lu à partir de la première chaîne de caractères d'un fichier d'entrée dans chaque ligne, la valeur de frameTypeHash est réalisé en divisant la ligne restante et a été stocké comme objet Chaîne initialement, sur une période de temps, le fichier a commencé à avoir plusieurs lignes (avec des valeurs différentes) associés avec la même clé de frameID, de sorte frameTypeHash a été remplacée par la dernière ligne en tant que valeur. Je l'ai remplacé l'objet String avec un autre objet HashMap que le champ de valeur, ce qui a contribué à maintenir la clé unique à la cartographie de valeur différente.
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;
}
}
Pouvez-vous expliquer également le contexte pour lequel vous essayez de mettre en œuvre une carte avec les clés en double? Je suis sûr qu'il pourrait y avoir une meilleure solution. Les cartes sont destinées à maintenir des clés uniques pour une bonne raison. Bien que si vous vouliez vraiment le faire; vous pouvez toujours étendre la classe écrire une simple classe carte personnalisée qui a une fonction d'atténuation des collisions et qui vous permettra de garder les entrées multiples avec les mêmes clés.
Note: Vous devez implémenter la fonction d'atténuation des collisions telles que les clés entrant en collision sont converties en ensemble unique « toujours ». Quelque chose de simple comme, clé avec hashcode annexant objet ou quelque chose?
juste pour être complet, Apache Commons Collections a également MultiMap . L'inconvénient est bien sûr que Apache Commons n'utilise pas Generics.
Avec un peu pirater, vous pouvez utiliser HashSet avec des clés en double. AVERTISSEMENT: cela dépend fortement HashSet mise en œuvre.
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);
}
}
Si des clés en double alors une clé peut correspondre à plus d'une valeur. La solution évidente consiste à cartographier la clé d'une liste de ces valeurs.
Par exemple en 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
je ceci:
java.util.List<java.util.Map.Entry<String,Integer>> pairList= new java.util.ArrayList<>();
1, Map<String, List<String>> map = new HashMap<>();
cette solution verbeux a de multiples inconvénients et est sujette à des erreurs. Il implique que nous devons instancier une collection pour chaque valeur, vérifiez sa présence avant d'ajouter ou de supprimer une valeur, supprimer manuellement en l'absence de les valeurs sont à gauche, etcetera.
2, org.apache.commons.collections4.MultiMap interface
3, com.google.common.collect.Multimap interface
Qu'en est-il un tel impl 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() .....
}