Frage
Ich versuche Häufigkeit von Wörtern in einer Textdatei zu zählen. Aber ich habe einen anderen Ansatz zu verwenden. Zum Beispiel, wenn die Datei enthält BRAIN-ISCHÄMIE und ISCHÄMIE-BRAIN, ich brauche zweimal BRAIN-ISCHÄMIE zu zählen oder umgekehrt (und ISCHÄMIE-BRAIN verlassen). Hier ist mein Stück Code -
// 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);
Aber für die folgende Datei -
ISCHÄMIE-GLUTAMAT ISCHÄMIE-BRAIN Glutamat BRAIN BRAIN-TOLERIEREN BRAIN-TOLERIEREN TOLERIEREN-BRAIN Glutamat ISCHÄMIE Ischämisch GLUTAMAT
Ich erhalte die folgende Ausgabe -
{Glutamat-Hirn = 1, Ischämie-Glutamat = 3, Ischämie-Hirn = 1, Glutamat-Ischämie = 3, Gehirn-tolerieren = 3, Gehirn-Ischämie = 1, tolerieren-Hirn = 3, Gehirn-Glutamat = 1}
Das Problem ist in der zweiten, während Block denke ich. Jedes Licht auf dieses Problem wird sehr geschätzt werden.
Lösung
Von einer Algorithmus Perspektive, können Sie den folgenden Ansatz in Erwägung ziehen:
Für jede Zeichenfolge, geteilt, dann sortieren, dann wieder verbinden (das heißt nehmen DEF-ABC und Konvertit ABC-DEF. ABC-DEF ABC-DEF umwandeln würde). Dann verwenden, als Schlüssel für Ihre Frequenzzählung.
Wenn Sie auf die genaue ursprüngliche Element zu halten, benötigen, sind nur, dass in Ihren Schlüssel - so würde der Schlüssel: Ordnungs (die Wieder kombinierte String) und original
.Andere Tipps
Disclaimer:. Ich habe den süß Trick vorgeschlagen von Kevin Day für meine Implementierung
Ich möchte immer noch nur schreiben, um Ihnen mitzuteilen, dass die richtige Datenstruktur ( Multiset / Bad ) und die richtigen Bibliotheken ( google-Guave ) wird nicht nur simplify der Code, sondern macht es auch effizient .
Code
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;
}
}
Ausgabe
BRAIN-TOLERATE = 3
ISCHEMIA-GLUTAMATE = 3
GLUTAMATE-BRAIN = 1
ISCHEMIA-BRAIN = 1
Vielen Dank allen für Ihre Hilfe. Hier ist, wie ich es gelöst -
// 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);