Domanda
sto provando a contare la frequenza di parole in un file di testo. Ma devo usare un approccio diverso. Ad esempio, se il file contiene BRAIN-ischemia e ischemia CERVELLO, ho bisogno di contare CERVELLO ISCHEMIA due volte (e lasciando ischemia cerebrale) o viceversa. Qui è il mio pezzo di codice -
// 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);
Ma per il seguente file -
ISCHEMIA-glutammato ISCHEMIA-CERVELLO Glutammato CERVELLO BRAIN-TOLLERARE BRAIN-TOLLERARE TOLLERARE-CERVELLO Glutammato ISCHEMIA ISCHEMIA-glutammato
Sto ottenendo il seguente output -
{glutammato cerebrale = 1, ischemia-glutammato = 3, ischemia cerebrale = 1, glutammato-ischemia = 3, il cervello-tollera = 3, il cervello-ischemia = 1, tollerare-encefalica = 3, brain-glutammato = 1}
Il problema è nel secondo mentre blocco credo. Luce su questo problema sarà molto apprezzato.
Soluzione
Dal punto di vista algoritmo, si può prendere in considerazione il seguente approccio:
Per ogni stringa, divisione, quindi ordinare, quindi ricombinare (cioè prendere DEF-ABC e convertire ABC-DEF. ABC-DEF convertirebbe ABC-DEF). Quindi utilizzare che come chiave per il valore di frequenza.
Se avete bisogno di tenere su l'elemento originale esatto, è sufficiente includere che nella vostra chiave - così la chiave sarebbe: ordinali (la stringa di ri-combinazione) e originale
.Altri suggerimenti
. Disclaimer: ho rubato la dolce trucco suggerita da Kevin Day per la mia realizzazione
ho ancora voglia di postare solo farvi sapere che utilizzando la struttura dati destra ( Multiset / Bad ) e le librerie di destra ( google-guava ) non solo semplificare il codice, ma rende anche efficace .
Codice
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;
}
}
Output
BRAIN-TOLERATE = 3
ISCHEMIA-GLUTAMATE = 3
GLUTAMATE-BRAIN = 1
ISCHEMIA-BRAIN = 1
Grazie a tutti per il vostro aiuto. Ecco come ho risolto -
// 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);