# String Arrays - häufigste Wörter



## clemensum (18. Jun 2011)

Meine Aufgabe besteht u.a. darin, dass ich die zehn häufigsten Wörter einer eingelesenen Textdatei (z.B. eine Passage aus dem Faust) mithilfe Java-Programmierung bestimmen soll. 

Ich bin elementar vorgegangen und noch nicht ganz fertig (was durchaus zulässig ist) und habe mir einen einfachen Algorithmus überlegt, welchen ich nun kurz in Worten fassen möchte:
Das erste Wort des Arrays wird mit allen anderen Wortes des Arrays auf (String-)Gleichheit überprüft. Gilt die Gleichheit, so wird ein Zähler um eins erhöht. 
Genauso für das zweite Wort, wobei es mit den anderen Worten ab dem 1. Arrayelement wieder verglichen wird. 
Auf eines muss man jedoch achten: Es ist sinnlos ein schon einmal verglichenes Wort wieder mit den anderen auf Gleichheit zu untersuchen, daher habe ich ein Hilfsarray definiert, wo alle bisherigen Startwörter eingefügt werden. In der if-Abfrage soll nun geschaut werden, ob das neue Startelement schon einmal als ein solches vorgekommen ist. 
Beispielarray: 
[Mutter, Esel, Liebe, Hass, Esel, Mutter, Garten, Hase, Baum, Hase, Käfer, Eva, Wald, Baum] 
Das Wort "Mutter" wird nun mit allen anderen Elementen des Arrays auf Gleichheit verglichen. 
Jedoch: Wenn array[j] bei der zweiten "Mutter" angelangt ist, muss nicht mehr mit den anderen worten auf Gleichheit überprüft werden, denn das ist ja schon passiert. Dieser Umstand führt auf die Idee ein Hilfsarray einzuführen, in dem alle Wörter stehen, die schon mit allen anderen verglichen wurden. Es wird deshalb in einer if-Abfrage geschaut, ob array[j] schon im Hilfsarray hilfsarray vorkommt. Wenn ja, dann kann der Vergleich in diesem inneren Schleifenduechgang ausfallen, wenn nein...  (ich hoffe, es ist klar geworden, was meine Idee diesbezüglich ist) 

Nun der Code: 

```
static String zehnhäufigstenWörter(Integer[] array) {
		int i, j = 0, zähler = 0;
		int[] hilfsarray = new int[array.length];
		//while (j < array.length) {
			//hilfsarray[j] = array[j];
			//j++;
		//}
		
		while (j < array.length) {
			i = 0;
			while (i < array.length) {
	if (array[j].equals(array[i]) && !array[j].equals(hilfsarray[j]) )  //hier, rechts vom UND-Symbol sollte dieser Befehl hinein, wo ich abfrage, ob das Anfangselement denn nicht schon einmal ein solches war und daher nicht mehr mit den anderen verglichen werden muss. 


 {
					zähler++; 
				hilfsarray[j] = array[j]; 
				
				}
				i++;
			}
			j++;
		}
	}
```

Meine kommentierter Code (siehe if-Abfrage) ist natürlich ein semantischer Unsinn. Ich habe jedoch keinen Befehl gefunden mit dem ich nachfragen kann, ob denn das neue array[j] denn nicht schon im Hilfsarray vorkommt. Ich möchte also abfragen: Ist array[j]  € hilfsarray? (wobei das Eurozeichen an das mathematische Elementzeichen erinnern soll).  
Ich wollt euch nun fragen, ob es denn so einen Befehl überhaupt gibt, oder muss ich dies extra mit einer weiteren Schleife abprüfen, ob array[j] ein Element von hilfsarray ist?


----------



## Gast2 (18. Jun 2011)

Darfst du auch andere Datenstrukturen verwenden?
Dann würd ich dir zu dem TreeSet raten. Zusätzlich kontruierst du dir noch einen eigenen Datentyp der ein Wort und seine Häufigkeit umfasst. Den kannst du dann ins TreeSet packen.

EDIT:
Grad wiedergefunden, vllt kannste dir da nen paar Ideen abschaun.


```
public static void main(String[] args) {		
		String text = "I have a blue house with a blue window Blue is the colour of all that I wear Blue are the streets and all the trees are too I have a girlfriend and she is so blue";
		
		WordFrequencyAnalysis wfa = new WordFrequencyAnalysis(false);
		wfa.add(text);
		
		Set<WordFrequency> frequencies = wfa.getWordFrequencies();
		
		for (WordFrequency wf : frequencies) {
			System.out.println(wf.getWord() + " -> " + wf.getFrequency());
		}
	}
```


```
public class WordFrequencyAnalysis {

	private Map<String, WordFrequency> wordFrequencies;
	private boolean caseSensitive; 
	
	public WordFrequencyAnalysis() {
		this(false);
	}
	
	public WordFrequencyAnalysis(boolean caseSensitive) {
		wordFrequencies = new HashMap<String, WordFrequency>();
		this.caseSensitive = caseSensitive;
	}
	
	public void add(String text) {		
		// remove punctuation marks
		text = text.replaceAll(",|\\.|!|\\?|-|_", "");
		
		StringTokenizer tokenizer = new StringTokenizer(text);
		while (tokenizer.hasMoreTokens()) {
			String token = tokenizer.nextToken();
			addWord(token);
		}
	}
	
	private void addWord(String word) {
		if (!isCaseSensitive()) {
			word = word.toLowerCase();
		}
		
		if (wordFrequencies.containsKey(word)) {
			wordFrequencies.get(word).incrementFreqency();
		} else {
			wordFrequencies.put(word, new WordFrequency(word));
		}
	}
	
	public Set<WordFrequency> getWordFrequencies() {
		Set<WordFrequency> wfSet = new TreeSet<WordFrequency>();
		
		for (Map.Entry<String, WordFrequency> entry : wordFrequencies.entrySet()) {
			wfSet.add(entry.getValue());
		}
		
		return wfSet;
	}
	
	public int getWordFrequency(String word) {
		if (!wordFrequencies.containsKey(word)) {
			return 0;
		}
		
		return wordFrequencies.get(word).getFrequency();
	}
	
	public boolean isCaseSensitive() {
		return caseSensitive;
	}
}
```


```
public class WordFrequency implements Comparable<WordFrequency> {
	private String word;
	private int frequency;
	
	public WordFrequency(String word) {
		this.word = word;
		frequency = 1;
	}
	
	public void incrementFreqency() {
		incrementFrequency(1);
	}
	
	public void incrementFrequency(int i) {
		frequency += i;
	}
	
	public String getWord() {
		return word;
	}
	
	public int getFrequency() {
		return frequency;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + frequency;
		result = prime * result + ((word == null) ? 0 : word.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		WordFrequency other = (WordFrequency) obj;
		if (frequency != other.frequency)
			return false;
		if (word == null) {
			if (other.word != null)
				return false;
		} else if (!word.equals(other.word))
			return false;
		return true;
	}

	@Override
	public int compareTo(WordFrequency o) {
		if (frequency == o.frequency) {
			return word.compareTo(o.word);
		}
		
		return frequency < o.frequency ? 1 : -1;
	}
}
```


----------



## clemensum (19. Jun 2011)

```
text = text.replaceAll(",|\\.|!|\\?|-|_", "");
```

Wie kann ich daraus ablesen, welche Sonderzeichen der Compiler durch "nichts" ersetzt??? 
Wie könnte ich z.B. ihm sagen, dass er Dollerzeichen auch ignorieren soll, so? 


```
text = text.replaceAll(",|\\.|!|\\?|-|_ //$", "");
```
Es scheint nirgenwoe in der API zu stehen, wie man genau die Sonderzeichen hineinschreiben soll, es steht nur, was der Befehl macht... :bahnhof: 

Hat da jemand eine Idee?


----------



## eRaaaa (19. Jun 2011)

//$ --> \\$

manche Sonderzeichen müssen im Regex escaped werden, da sie sonst eine Sonderaufgabe haben!
z.B. eben der Punkt, der steht auch für jedes Zeichen! Wenn du nun aber den Punkt meinst, musst du den maskieren mit \\ und nicht mit // 

Das ODER kannst du dir eig. auch sparen -> "[,\\.!\\?\\-_\\$]"

EDIT: @EikeB: den hashcode nachträglich zu ändern ist gefährlich


----------



## clemensum (19. Jun 2011)

Hallo liebe Java-Programmierer!  

Da wir in der Vorlesung die Maps noch nicht hatten und ich mich dort erst gerade mühsam einarbeiten muss und trotzdem bis nächste Woche eine Arbeit abzugeben habe, bitte ich euch um einen Tipp, wie man aus dem obig angegebenen Code, d.h. aus den drei Klassen für die Worthäufigkeiten, die zehn häufigsten Worte ermitteln kann. D.h., ich bitte euch, mir die Stelle zu sagen, wo ich das entsprechend ändern kann, weil ich kann dies ( noch ) nicht richtig erkennen! :bahnhof:

Meine Vermutung ist, dass man in der main-Methode dazu eine Schleife einbauen muss, die nur die ersten zehn Worte ausgeben, statt alle, habe ich recht?

EDIT: Ich meine die drei Klassen von EikeB. :rtfm:


----------



## Marcinek (19. Jun 2011)

Zähle doch alle Wörter und gebe die häufisten aus? ;D

Dazu nimmst du dir entweder eine ArrayList oder machst dir ein selbst wachsendes Array.

Gruß

Martin


----------



## Volvagia (19. Jun 2011)

Was spricht gegen eine HashMap?


```
public void addWord(String word)
{
	Integer count = map.get(word);
	if(count == null)
	{
		map.put(word, 1);
		return;
	}
	count++; //Sollte durch Autoboxing möglich sein, aber nicht zu 100% sicher.
	map.put(word, count);
}
```

Oder so ähnlich. Vorteil: Sehr schneller Zugriff. Nachteil: Unsortiert, also musst du am Ende selbst rausfinden, wo die höchste Anzahl steht, aber ist ein Klacks.


----------



## Gast2 (19. Jun 2011)

Ich verwende doch ne map? Oder wen meinst du?
Statt nem einfachen Integer pack ich halt nen eigenen Datentypen rein.

@eRaaaa:
Danke, merk ich mir


----------



## eRaaaa (19. Jun 2011)

EikeB hat gesagt.:


> *@SlaterB:*
> Danke, merk ich mir



Gibt`s hier noch ne` Seite? ???:L


----------



## Gast2 (19. Jun 2011)

Hm, hab wohl noch nicht ausgeschlafen, meinte natürlich dich eRaaaa


----------



## clemensum (19. Jun 2011)

Danke für eure Antwort, liebe Leute, aber, ihr meint schon die main-Methode, wo ich die Array-List einfügen kann, oder?


----------

