Serait-il possible d'ajouter un ArrayList
comme clé de HashMap
. Je voudrais conserver le nombre de fréquences des bigrammes. Le bigramme est la clé et la valeur est sa fréquence.
Pour chacun des bigrammes comme "il est", je crée un ArrayList
pour lui et l'insère dans le HashMap
. Mais je n'obtiens pas la sortie correcte.
public HashMap<ArrayList<String>, Integer> getBigramMap(String Word1, String Word2) {
HashMap<ArrayList<String>, Integer> hm = new HashMap<ArrayList<String>, Integer>();
ArrayList<String> arrList1 = new ArrayList<String>();
arrList1 = getBigram(Word1, Word2);
if (hm.get(arrList1) != null) {
hm.put(arrList1, hm.get(arrList1) + 1);
} else {
hm.put(arrList1, 1);
}
System.out.println(hm.get(arrList1));
return hm;
}
public ArrayList<String> getBigram(String Word1, String Word2) {
ArrayList<String> arrList2 = new ArrayList<String>();
arrList2.add(Word1);
arrList2.add(Word2);
return arrList2;
}
Oui, vous pouvez avoir ArrayList
s comme clés dans une carte de hachage, mais c'est un très mauvaise idée car ils sont mutables.
Si vous modifiez le ArrayList
de quelque façon que ce soit (ou l'un de ses éléments), le mappage sera fondamentalement perdu, car la clé n'aura pas le même hashCode
que lors de son insertion .
La règle d'or consiste à n'utiliser que des types de données immuables comme clés dans une carte de hachage. Comme suggéré par Alex Stybaev, vous souhaiterez probablement créer une classe Bigram
comme ceci:
final class Bigram {
private final String Word1, Word2;
public Bigram(String Word1, String Word2) {
this.Word1 = Word1;
this.Word2 = Word2;
}
public String getWord1() {
return Word1;
}
public String getWord2() {
return Word2;
}
@Override
public int hashCode() {
return Word1.hashCode() ^ Word2.hashCode();
}
@Override
public boolean equals(Object obj) {
return (obj instanceof Bigram) && ((Bigram) obj).Word1.equals(Word1)
&& ((Bigram) obj).Word2.equals(Word2);
}
}
De la documentation :
Remarque: une grande prudence doit être exercée si des objets mutables sont utilisés comme clés de carte. Le comportement d'une carte n'est pas spécifié si la valeur d'un objet est modifiée d'une manière qui affecte les comparaisons
equals
alors que l'objet est une clé de la carte. Un cas particulier de cette interdiction est qu'il n'est pas permis à une carte de se contenir comme clé. S'il est permis à une carte de se contenir en tant que valeur, une extrême prudence est conseillée: les méthodesequals
ethashCode
ne sont plus bien définies sur une telle carte.
Vous devez faire attention lorsque vous utilisez des objets mutables comme clés pour le bien de hashCode
et equals
.
L'essentiel est qu'il est préférable d'utiliser des objets immuables comme clés.
Pourquoi ne pouvez-vous pas utiliser quelque chose comme ça:
class Bigram{
private String firstItem;
private String secondItem;
<getters/setters>
@Override
public int hashCode(){
...
}
@Override
public boolean equals(){
...
}
}
au lieu d'utiliser la collection dynamique pour un nombre limité d'éléments (deux).
J'ai trouvé cette solution. Il n'est évidemment pas utilisable dans tous les cas, par exemple en cas de dépassement de la capacité int de hashcodes, ou de complications list.clone () (si la liste d'entrée est modifiée, la clé reste la même que prévu, mais lorsque les éléments de List sont mutables, clonés liste a la même référence à ses éléments, ce qui entraînerait la modification de la clé elle-même).
import Java.util.ArrayList;
public class ListKey<T> {
private ArrayList<T> list;
public ListKey(ArrayList<T> list) {
this.list = (ArrayList<T>) list.clone();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
for (int i = 0; i < this.list.size(); i++) {
T item = this.list.get(i);
result = prime * result + ((item == null) ? 0 : item.hashCode());
}
return result;
}
@Override
public boolean equals(Object obj) {
return this.list.equals(obj);
}
}
---------
public static void main(String[] args) {
ArrayList<Float> createFloatList = createFloatList();
ArrayList<Float> createFloatList2 = createFloatList();
Hashtable<ListKey<Float>, String> table = new Hashtable<>();
table.put(new ListKey(createFloatList2), "IT WORKS!");
System.out.println(table.get(createFloatList2));
createFloatList2.add(1f);
System.out.println(table.get(createFloatList2));
createFloatList2.remove(3);
System.out.println(table.get(createFloatList2));
}
public static ArrayList<Float> createFloatList() {
ArrayList<Float> floatee = new ArrayList<>();
floatee.add(34.234f);
floatee.add(new Float(33));
floatee.add(null);
return floatee;
}
Output:
IT WORKS!
null
IT WORKS!
Essayez ceci, cela fonctionnera.
public Map<List, Integer> getBigramMap (String Word1,String Word2){
Map<List,Integer> hm = new HashMap<List, Integer>();
List<String> arrList1 = new ArrayList<String>();
arrList1 = getBigram(Word1, Word2);
if(hm.get(arrList1) !=null){
hm.put(arrList1, hm.get(arrList1)+1);
}
else {
hm.put(arrList1, 1);
}
System.out.println(hm.get(arrList1));
return hm;
}
Bien sûr, c'est possible. Je suppose que le problème dans votre put
. Essayez d'obtenir la clé pour le bigramme, incrémentez-la, supprimez l'entrée avec ce bigramme et insérez la valeur mise à jour