HashMap avec plusieurs valeurs sous la même clé
Est-il possible pour nous d'implémenter un HashMap avec une clé et deux valeurs. Tout comme table de hachage?
Veuillez m'aider, aussi en disant (s'il n'y a aucun moyen) une autre façon d'implémenter le stockage de trois valeurs avec une comme clé?
19 réponses
Vous pourriez:
- utilisez une carte dont la valeur est une liste.
Map<KeyType, List<ValueType>>
. - créez une nouvelle classe wrapper et placez les instances de ce wrapper dans la carte.
Map<KeyType, WrapperType>
. - utilisez un tuple comme classe (enregistre la création de beaucoup de wrappers).
Map<KeyType, Tuple<Value1Type, Value2Type>>
. - Utilisez plusieurs cartes côte à côte.
Exemples
1. Carte avec liste comme valeur
// create our map
Map<String, List<Person>> peopleByForename = new HashMap<>();
// populate it
List<Person> people = new ArrayList<>();
people.add(new Person("Bob Smith"));
people.add(new Person("Bob Jones"));
peopleByForename.put("Bob", people);
// read from it
List<Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs[0];
Person bob2 = bobs[1];
L'inconvénient de cette approche est que la liste n'est pas lié à exactement deux valeur.
2. Utilisation de la classe wrapper
// define our wrapper
class Wrapper {
public Wrapper(Person person1, Person person2) {
this.person1 = person1;
this.person2 = person2;
}
public Person getPerson1 { return this.person1; }
public Person getPerson2 { return this.person2; }
private Person person1;
private Person person2;
}
// create our map
Map<String, Wrapper> peopleByForename = new HashMap<>();
// populate it
Wrapper people = new Wrapper()
peopleByForename.put("Bob", new Wrapper(new Person("Bob Smith"),
new Person("Bob Jones"));
// read from it
Wrapper bobs = peopleByForename["Bob"];
Person bob1 = bobs.Person1;
Person bob2 = bobs.Person2;
L'inconvénient de cette approche est que vous devez écrire beaucoup de code de Plaque de chaudière pour toutes ces classes de conteneurs très simples.
3. Utilisation d'un tuple
// you'll have to write or download a Tuple class in Java, (.NET ships with one)
// create our map
Map<String, Tuple2<Person, Person> peopleByForename = new HashMap<>();
// populate it
peopleByForename.put("Bob", new Tuple2(new Person("Bob Smith",
new Person("Bob Jones"));
// read from it
Tuple<Person, Person> bobs = peopleByForename["Bob"];
Person bob1 = bobs.Item1;
Person bob2 = bobs.Item2;
C'est la meilleure solution, à mon avis.
4. Plusieurs cartes
// create our maps
Map<String, Person> firstPersonByForename = new HashMap<>();
Map<String, Person> secondPersonByForename = new HashMap<>();
// populate them
firstPersonByForename.put("Bob", new Person("Bob Smith"));
secondPersonByForename.put("Bob", new Person("Bob Jones"));
// read from them
Person bob1 = firstPersonByForename["Bob"];
Person bob2 = secondPersonByForename["Bob"];
L'inconvénient de cette solution est qu'il n'est pas évident que les deux cartes sont liées, une erreur programmatique pourrait voir les deux cartes sortir de la synchronisation.
Non, pas seulement comme un HashMap
. Vous auriez essentiellement besoin d'un HashMap
d'une clé à une collection de valeurs.
Si vous êtes heureux d'utiliser des bibliothèques externes, Goyave est exactement ce concept dans Multimap
avec des implémentations telles que ArrayListMultimap
et HashMultimap
.
Un autre bon choix est d'utiliser MultiValuedMap D'Apache Commons. Jetez un oeil à la Toutes les Classes D'implémentation connues en haut de la page pour les implémentations spécialisées.
Exemple:
HashMap<K, ArrayList<String>> map = new HashMap<K, ArrayList<String>>()
Pourrait être remplacé par
MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
Donc,
map.put(key, "A");
map.put(key, "B");
map.put(key, "C");
Collection<String> coll = map.get(key);
Résulterait en une collection coll
contenant "A", " B " et "C".
Jetez un oeil à Multimap
à partir des bibliothèques goyave et de son implémentation - HashMultimap
Une collection similaire à une Carte, mais qui peut associer plusieurs valeurs avec une seule clé. Si vous appelez put (K, V) deux fois, avec la même clé mais des valeurs différentes, le multimap contient des mappages de la clé vers les deux valeurs.
J'utilise Map<KeyType, Object[]>
, pour associer plusieurs valeurs avec une clé dans une Carte. De cette façon, je peux stocker plusieurs valeurs de différents types associés à une clé. Vous devez prendre soin de maintenir l'ordre d'insertion et de récupération de L'objet[].
Exemple: Considérez, nous voulons stocker des informations sur les étudiants. La clé est id, alors que nous aimerions stocker le nom, l'adresse et l'email associés à l'étudiant.
//To make entry into Map
Map<Integer, String[]> studenMap = new HashMap<Integer, String[]>();
String[] studentInformationArray = new String[]{"name", "address", "email"};
int studenId = 1;
studenMap.put(studenId, studentInformationArray);
//To retrieve values from Map
String name = studenMap.get(studenId)[1];
String address = studenMap.get(studenId)[2];
String email = studenMap.get(studenId)[3];
HashMap<Integer,ArrayList<String>> map = new HashMap<Integer,ArrayList<String>>();
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add("xyz");
map.put(100,list);
Juste pour l'enregistrement, la solution pure JDK8 serait d'utiliser la méthode Map::compute
:
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
Tels que
public static void main(String[] args) {
Map<String, List<String>> map = new HashMap<>();
put(map, "first", "hello");
put(map, "first", "foo");
put(map, "bar", "foo");
put(map, "first", "hello");
map.forEach((s, strings) -> {
System.out.print(s + ": ");
System.out.println(strings.stream().collect(Collectors.joining(", ")));
});
}
private static <KEY, VALUE> void put(Map<KEY, List<VALUE>> map, KEY key, VALUE value) {
map.compute(key, (s, strings) -> strings == null ? new ArrayList<>() : strings).add(value);
}
, Avec sortie:
bar: foo
first: hello, foo, hello
Notez que pour assurer la cohérence dans le cas où plusieurs threads accèdent à cette structure de données, ConcurrentHashMap
et CopyOnWriteArrayList
par exemple, doivent être utilisés.
Si vous utilisez Framework Spring. Il y a: org.springframework.util.MultiValueMap
.
Pour créer une carte multi-valeurs non modifiable:
Map<String,List<String>> map = ...
MultiValueMap<String, String> multiValueMap = CollectionUtils.toMultiValueMap(map);
Ou utiliser org.springframework.util.LinkedMultiValueMap
Oui et non. La solution consiste à construire un wrapper clas pour vos valeurs qui contient les 2 (3, ou plus) valeurs qui correspondent à votre clé.
Le moyen le plus simple serait d'utiliser une bibliothèque de collection google:
Importer com.Google.commun.recueillir.ArrayListMultimap; import com.Google.commun.recueillir.Multimap;
Test de classe publique {
public static void main(final String[] args) {
// multimap can handle one key with a list of values
final Multimap<String, String> cars = ArrayListMultimap.create();
cars.put("Nissan", "Qashqai");
cars.put("Nissan", "Juke");
cars.put("Bmw", "M3");
cars.put("Bmw", "330E");
cars.put("Bmw", "X6");
cars.put("Bmw", "X5");
cars.get("Bmw").forEach(System.out::println);
// It will print the:
// M3
// 330E
// X6
// X5
}
}
Lien Maven: https://mvnrepository.com/artifact/com.google.collections/google-collections/1.0-rc2
Plus à ce sujet: http://tomjefferys.blogspot.be/2011/09/multimaps-google-guava.html
Je n'ai pas pu poster de réponse sur le commentaire de Paul, donc je crée un nouveau commentaire pour Vidhya ici:
Wrapper sera un SuperClass
pour les deux classes que nous voulons pour stocker une valeur.
Et à l'intérieur de la classe wrapper, nous pouvons mettre les associations comme objets variables d'instance pour les deux objets de classe.
Par exemple
class MyWrapper {
Class1 class1obj = new Class1();
Class2 class2obj = new Class2();
...
}
Et en HashMap, nous pouvons mettre de cette façon,
Map<KeyObject, WrapperObject>
WrapperObj aura variables de classe: class1Obj, class2Obj
Vous pouvez le faire implicitement.
// Create the map. There is no restriction to the size that the array String can have
HashMap<Integer, String[]> map = new HashMap<Integer, String[]>();
//initialize a key chosing the array of String you want for your values
map.put(1, new String[] { "name1", "name2" });
//edit value of a key
map.get(1)[0] = "othername";
C'est très simple et efficace. Si vous voulez des valeurs de différentes classes à la place, vous pouvez faire ce qui suit:
HashMap<Integer, Object[]> map = new HashMap<Integer, Object[]>();
Peut être fait en utilisant un identityHashMap, soumis à la condition que la comparaison des clés soit faite par = = operator et non equals ().
Je préfère ce qui suit pour stocker n'importe quel nombre de variables sans avoir à créer une classe séparée.
final public static Map<String, Map<String, Float>> myMap = new HashMap<String, Map<String, Float>>();
Voici la réponse :):)
Chaîne clé = "services_servicename"
Données ArrayList;
Pour (int i = 0; I lessthen données.size (); I++) {
HashMap<String, String> servicesNameHashmap = new HashMap<String, String>();
servicesNameHashmap.put(key,data.get(i).getServiceName());
mServiceNameArray.add(i,servicesNameHashmap); }
J'ai les meilleurs résultats.
Il vous suffit de créer un nouveau HashMap comme
HashMap servicesNameHashmap = new HashMap ();
Dans Votre Boucle For. Il aura le même effet comme la même clé et plusieurs valeurs.
Codage Heureux:)
Je suis tellement habitué à faire cela avec un dictionnaire de données dans Objective C. Il était plus difficile d'obtenir un résultat similaire en Java pour Android. J'ai fini par créer une classe personnalisée, puis juste faire un hashmap de ma classe personnalisée.
public class Test1 {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addview);
//create the datastring
HashMap<Integer, myClass> hm = new HashMap<Integer, myClass>();
hm.put(1, new myClass("Car", "Small", 3000));
hm.put(2, new myClass("Truck", "Large", 4000));
hm.put(3, new myClass("Motorcycle", "Small", 1000));
//pull the datastring back for a specific item.
//also can edit the data using the set methods. this just shows getting it for display.
myClass test1 = hm.get(1);
String testitem = test1.getItem();
int testprice = test1.getPrice();
Log.i("Class Info Example",testitem+Integer.toString(testprice));
}
}
//custom class. You could make it public to use on several activities, or just include in the activity if using only here
class myClass{
private String item;
private String type;
private int price;
public myClass(String itm, String ty, int pr){
this.item = itm;
this.price = pr;
this.type = ty;
}
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public String getType() {
return item;
}
public void setType(String type) {
this.type = type;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
Nous pouvons créer une classe pour avoir plusieurs clés ou valeurs et l'objet de cette classe peut être utilisé comme paramètre dans map. Vous pouvez vous référer à https://stackoverflow.com/a/44181931/8065321
Essayez LinkedHashMap , Exemple:
Map<String,String> map = new LinkedHashMap<String,String>();
map.put('1','linked');map.put('1','hash');
map.put('2','map');map.put('3','java');..
Sortie:
Clés: 1,1,2,3
Valeurs: lié,hachage, carte, java