1
votes

L'incrémentation des valeurs de HashMap pour la fréquence clé ne s'imprime pas

Je travaille actuellement sur un projet pour compter la fréquence des mots dans un fichier texte. Le programme pilote place les mots dans un ArrayList (après les avoir mis en minuscules et en supprimant les espaces), puis l'objet FreqCount place le ArrayList dans un HashMap qui gérera les opérations de fréquence. Jusqu'à présent, je peux demander au pilote de lire le fichier texte, de le mettre dans une ArrayList, puis de le placer dans le HashMap. Mon problème est que les nœuds HashMap ne se répètent pas, donc j'essaie d'incrémenter la valeur chaque fois que le mot est vu.

Chauffeur:

one,
one,
one,
one
one
one
one
one
one
one
one
one
one
one
one
one
one
eleven
ten
nine
eight
seven
six
five
four
three
two
one

 Hashmap: 

key: nine value: 1
key: one, value: 1
key: six value: 1
key: four value: 1
key: one value: 1
key: seven value: 1
key: eleven value: 1
key: ten value: 1
key: five value: 1
key: three value: 1
key: two value: 1
key: eight value: 1

FreqCount:

ONE TWO ThReE FoUR fIve
six     seven        
EIGHT
     NINE       
TEN ELEVEN
ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE ONE, ONE, ONE,

Fichier texte:

package threetenProg3;

import java.util.HashMap;
import java.util.List;

public class FreqCount {
    //attributes and initializations
    private HashMap<String, Integer> map = new HashMap<String, Integer>();
    
    //constructors
    
    FreqCount(List<String> driverList){
        for(int dLIndex = driverList.size()-1; dLIndex>=0; dLIndex--) { //puts list into hashmap
            
            for(String mapKey : map.keySet()) {
                
                if(mapKey.equals(driverList.get(dLIndex))) {
                    int tval = map.get(mapKey);
                    
                    map.remove(mapKey);
                    
                    map.put(mapKey, tval+1);
                }else {
                    map.put(mapKey, 1);
                }
                
            }
                
        }
        
    }
    
    //methods
    
    public void printMap() {
        for (String i : map.keySet()) { //function ripped straight outta w3schools lol
              System.out.println("key: " + i + " value: " + map.get(i));
        }
    } //*/
    
}

Production:

package threetenProg3;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.ArrayList;


public class Driver {
    
    public static void main(String[] args) throws FileNotFoundException{
        File in = new File("test.txt");
        Scanner scanFile = new Scanner(in);
        
        ArrayList<String> parsed = new ArrayList<String>();
        
        
        while(scanFile.hasNext()) { //if this ends up cutting off bottom line, make it a do while loop
            parsed.add(scanFile.next().toLowerCase());
        }
        
        for(int i = parsed.size()-1; i>=0; i--) { //prints arraylist backwards
            System.out.println(parsed.get(i));
        } //*/
        
        FreqCount fc = new FreqCount(parsed);
        
        System.out.println("\n Hashmap: \n");
        fc.printMap();
        
        scanFile.close();
        
    }
}

D'après ce que je vois, la sortie devrait imprimer les valeurs correctes pour les fréquences des touches. Merci d'avance pour votre aide!


0 commentaires

3 Réponses :


1
votes

Vous pouvez modifier la définition de FreqCount comme suit:

FreqCount(List<String> driverList) {
    for (int dLIndex = driverList.size() - 1; dLIndex >= 0; dLIndex--) {
        String key = driverList.get(dLIndex);
        map.put(key, map.getOrDefault(key, 0) + 1);
    }
}

Sortie après ce changement:

 Hashmap: 

key: nine value: 1
key: one, value: 3
key: six value: 1
key: four value: 1
key: one value: 15
key: seven value: 1
key: eleven value: 1
key: ten value: 1
key: five value: 1
key: three value: 1
key: two value: 1
key: eight value: 1

Alternativement,

FreqCount(List<String> driverList) {
    for (int dLIndex = driverList.size() - 1; dLIndex >= 0; dLIndex--) {
        String key = driverList.get(dLIndex);
        if (map.get(key) == null) {
            map.put(key, 1);
        } else {
            map.put(key, map.get(key) + 1);
        }
    }
}

Map#getOrDefault renvoie la valeur à laquelle la clé spécifiée est mappée, ou la valeur par défaut si cette carte ne contient aucun mappage pour la clé.


2 commentaires

Cela ressemble exactement à ce dont j'ai besoin, mais après avoir retaper le code dans mon éclipse, il imprime toujours toutes les valeurs comme 1. Même copier-coller directement à partir d'ici dans le code produit les mêmes résultats. Pour être clair, cela s'est produit pour tous ces correctifs, pas seulement pour les vôtres.


Ça ne fait rien! J'ai supposé que c'était un problème d'éclipse et j'ai tout déplacé vers un nouveau projet. Ça fonctionne maintenant. Merci beaucoup!!



0
votes

Vous avez plusieurs problèmes là-bas.

one
one
one
one
one
one
one
one
one
one
one
one
one
one
one
one
one
eleven
ten
nine
eight
seven
six
five
four
three
two
one

 Hashmap: 

key: nine value: 1
key: six value: 1
key: four value: 1
key: one value: 18
key: seven value: 1
key: eleven value: 1
key: ten value: 1
key: five value: 1
key: three value: 1
key: two value: 1
key: eight value: 1

Vous faites une boucle for bizarre là-bas en essayant de parcourir une carte vide. Vous devez vérifier s'il y a une clé pour ce mot dans la carte, s'il y en a, vous en ajoutez une à la valeur et s'il n'y en a pas, vous ajoutez la nouvelle paire avec la valeur 1.

Et pour éviter le nombre avec des virgules ou des points (si vous le souhaitez, vous pouvez ajouter d'autres caractères à l'expression régulière que replaceAll prend comme paramètre)

while(scanFile.hasNext()) { //if this ends up cutting off bottom line, make it a do while loop
        String value = scanFile.next().toLowerCase();
        value = value.replaceAll("[,.]", "");
        parsed.add(value);
    }

La sortie est maintenant

FreqCount(List<String> driverList){
    for(int dLIndex = driverList.size()-1; dLIndex>=0; dLIndex--) { //puts list into hashmap
        if(map.get(driverList.get(dLIndex)) != null) {
            int tval = map.get(driverList.get(dLIndex));
            map.remove(driverList.get(dLIndex));
            map.put(driverList.get(dLIndex), tval+1);
        }else {
            map.put(driverList.get(dLIndex), 1);
        }
    }

}

sans répétitions sur les mots même avec des virgules et le décompte correct de chacun


1 commentaires

Merci! Je ne pense pas que nous ayons encore couvert les regex, je vais donc l'examiner plus en profondeur pour voir si c'est quelque chose que mon professeur veut ici.



1
votes

Le moyen le plus simple de le faire, imo, est d'utiliser la méthode Map.merge . La méthode prend la valeur précédente et applique une fonction de mappage. Dans ce cas, la deuxième valeur n'est pas utilisée. La première valeur est utilisée pour remplacer la valeur existante + 1. Ainsi, vous obtenez la fréquence d'occurrence des chaînes.

Notez également que j'ai changé notre classe pour utiliser une méthode d' parse qui renvoie la carte. Il n'est pas approprié de faire beaucoup de calculs dans un constructeur de classe.

Après avoir lu les valeurs.

class FreqCount {
    // attributes and initializations
    private Map<String, Integer> map =
            new HashMap<>();
    
    public Map<String, Integer> parse (List<String> driverList) {
        for (String str : driverList) {
            map.merge(str, 1, (v1,notUsed)->v1 + 1);
        }
        return map;
    }
}

impressions

nine=1
one,=3
six=1
four=1
one=15
seven=1
eleven=1
ten=1
five=1
three=1
two=1
eight=1

La classe modifiée

         
FreqCount fc = new FreqCount();
Map<String,Integer> map = fc.parse(parsed);
        
map.entrySet().forEach(System.out::println);


1 commentaires

Malheureusement, cela fait partie de la tâche que je ne peux pas utiliser ces fonctions de carte avancées (désolé aurais dû le mentionner). J'ai eu ma réponse mais merci beaucoup!