Pergunta
Estou tentando contar a frequência das palavras em um arquivo de texto. Mas eu tenho que usar uma abordagem diferente. Por exemplo, se o arquivo contiver a iscodemia cerebral e isquemia-cérebro, preciso contar a iscemia cerebral duas vezes (e deixar a isquemia-cérebro) ou vice-versa. Aqui está o meu pedaço de código-
// Mapping of String->Integer (word -> frequency)
HashMap<String, Integer> frequencyMap = new HashMap<String, Integer>();
// Iterate through each line of the file
String[] temp;
String currentLine;
String currentLine2;
while ((currentLine = in.readLine()) != null) {
// Remove this line if you want words to be case sensitive
currentLine = currentLine.toLowerCase();
temp=currentLine.split("-");
currentLine2=temp[1]+"-"+temp[0];
// Iterate through each word of the current line
// Delimit words based on whitespace, punctuation, and quotes
StringTokenizer parser = new StringTokenizer(currentLine);
while (parser.hasMoreTokens()) {
String currentWord = parser.nextToken();
Integer frequency = frequencyMap.get(currentWord);
// Add the word if it doesn't already exist, otherwise increment the
// frequency counter.
if (frequency == null) {
frequency = 0;
}
frequencyMap.put(currentWord, frequency + 1);
}
StringTokenizer parser2 = new StringTokenizer(currentLine2);
while (parser2.hasMoreTokens()) {
String currentWord2 = parser2.nextToken();
Integer frequency = frequencyMap.get(currentWord2);
// Add the word if it doesn't already exist, otherwise increment the
// frequency counter.
if (frequency == null) {
frequency = 0;
}
frequencyMap.put(currentWord2, frequency + 1);
}
}
// Display our nice little Map
System.out.println(frequencyMap);
Mas para o seguinte arquivo-
Isquemia-glutamato isquemia-cérebro-cérebro-tolerto cerebral tolerado-toler-broin-cérebro-isquemia-isquemia-glutamia glutamato-isquemia-glutamato
Estou recebendo a seguinte saída
{glutamato-cérebro = 1, isquemia-glutamato = 3, isquemia-cérebro = 1, glutamato-iscemia = 3, tolerado cerebral = 3, isquemia cerebral = 1, tolerado-cérebro = 3, glutamato cerebral = 1}
O problema está em segundo lugar enquanto o bloco, eu acho. Qualquer luz sobre esse problema será muito apreciada.
Solução
Do ponto de vista do algoritmo, convém considerar a seguinte abordagem:
Para cada string, dividir, classificar e depois se combinar (ou seja, pegue o Def-ABC e converta para ABC-DEF. ABC-DEF se converteria em ABC-DEF). Em seguida, use isso como a chave para sua contagem de frequência.
Se você precisar segurar o item original exato, basta incluir isso na sua chave - para que a chave teria: ordinal (a string re -combinada) e original.
Outras dicas
Isenção de responsabilidade: eu roubei o Doce truque sugerido por Kevin Day para minha implementação.
Eu ainda quero postar apenas para que você saiba que o uso da estrutura de dados correta (Multiset/ruim) e as bibliotecas certas (Google-guava) não apenas simplificar o código, mas também faz eficiente.
Código
public class BasicFrequencyCalculator
{
public static void main(final String[] args) throws IOException
{
@SuppressWarnings("unchecked")
Multiset<Word> frequency = Files.readLines(new File("c:/2.txt"), Charsets.ISO_8859_1, new LineProcessor() {
private final Multiset<Word> result = HashMultiset.create();
@Override
public Object getResult()
{
return result;
}
@Override
public boolean processLine(final String line) throws IOException
{
result.add(new Word(line));
return true;
}
});
for (Word w : frequency.elementSet())
{
System.out.println(w.getOriginal() + " = " + frequency.count(w));
}
}
}
public class Word
{
private final String key;
private final String original;
public Word(final String orig)
{
this.original = orig.trim();
String[] temp = original.toLowerCase().split("-");
Arrays.sort(temp);
key = temp[0] + "-"+temp[1];
}
@Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((getKey() == null) ? 0 : getKey().hashCode());
return result;
}
@Override
public boolean equals(final Object obj)
{
if (this == obj)
{
return true;
}
if (obj == null)
{
return false;
}
if (!(obj instanceof Word))
{
return false;
}
Word other = (Word) obj;
if (getKey() == null)
{
if (other.getKey() != null)
{
return false;
}
}
else if (!getKey().equals(other.getKey()))
{
return false;
}
return true;
}
@Override
public String toString()
{
return getOriginal();
}
public String getKey()
{
return key;
}
public String getOriginal()
{
return original;
}
}
Resultado
BRAIN-TOLERATE = 3
ISCHEMIA-GLUTAMATE = 3
GLUTAMATE-BRAIN = 1
ISCHEMIA-BRAIN = 1
Obrigado a todos pela sua ajuda. Aqui está como eu resolvi
// Mapping of String->Integer (word -> frequency)
TreeMap<String, Integer> frequencyMap = new TreeMap<String, Integer>();
// Iterate through each line of the file
String[] temp;
String currentLine;
String currentLine2;
while ((currentLine = in.readLine()) != null) {
temp=currentLine.split("-");
currentLine2=temp[1]+"-"+temp[0];
// Iterate through each word of the current line
StringTokenizer parser = new StringTokenizer(currentLine);
while (parser.hasMoreTokens()) {
String currentWord = parser.nextToken();
Integer frequency = frequencyMap.get(currentWord);
Integer frequency2 = frequencyMap.get(currentLine2);
// Add the word if it doesn't already exist, otherwise increment the
// frequency counter.
if (frequency == null) {
if (frequency2 == null)
frequency = 0;
else {
frequencyMap.put(currentLine2, frequency2 + 1);
break;
}//else
} //if (frequency == null)
frequencyMap.put(currentWord, frequency + 1);
}//while (parser.hasMoreTokens())
}//while ((currentLine = in.readLine()) != null)
// Display our nice little Map
System.out.println(frequencyMap);