Lärare: Mats Dahllöf och Markus Saers.
UPPSALA UNIVERSITET
Inst. f. lingvistik och filologi
Uppsala universitet

Övningspaket 3: Associativa datastrukturer

Under den här övningen ska vi titta lite på vad som krävs för att kunna använda egna objekt som nycklar i associativa datastrukturer. Vi kommer att använda oss av taggade ord som nyckel.

Taggade ord

Den struktur som ska läsas in är en enkel klass som innhåller två strängattribut: ett löpord och en ordklasstag.

/** * A class that represents a tagged token. */ public class TokenTag { private String token; private String tag; /** * Only constructable with two strings, one for the token * and one for the part of speech tag. */ public TokenTag(String token, String tag) { this.token = token; this.tag = tag; } }

Det är den här klassen vi ska bygga ut så att den går att använda som nyckel.

Eftersom det är en del av inlämningsuppgiften på PST1 att läsa in taggade ord tänker jag inte ge er källkoden för en klass som gör detta. Istället kommer ni att få en förkompilerad klass som ni kan använda. Det går naturligtvis bra att implemnetera en egen!

Jag kommer genomgående att använda denna testtext:

får+VB får+NN får+NN nej+IJ får+NN får+VB inte+NEG får+NN får+NN får+VB lamm+NN

Klassen TokenTag. [java]
Inläsningsklass för TokenTag. [class]
Dokumentation av klasserna TokenTag och TokenTagScanner. [html]
Testtexten som används här. [txt]

Uppgift 1

Skriv en testklass som skriver ut taggade ord. Den ska läsa in från System.in, och skriva ut varje ord på en egen rad. Använd TokenTagScanner för att läsa från System.in.

Du borde få ett resultat som liknar det här:

markuss@objekt$ java Test < test.txt TokenTag@de6ced TokenTag@c17164 TokenTag@1fb8ee3 TokenTag@61de33 TokenTag@14318bb TokenTag@ca0b6 TokenTag@10b30a7 TokenTag@1a758cb TokenTag@1b67f74 TokenTag@69b332 TokenTag@173a10f markuss@objekt$

Skriv en String toString()-metod för klassen TokenTag. Den låter oss styra vad som skrivs ut när vi försöker skriva ut objekt av klassen.

Börja med att skriva en metod som gör att de taggade orden ser ut som de gjorde när de lästes in:

markuss@objekt$ java Test < test.txt får+VB får+NN får+NN nej+IJ får+NN får+VB inte+NEG får+NN får+NN får+VB lamm+NN markuss@objekt$

För resten av den här övningen kommer det att vara bra att hålla koll på att de faktiskt är olika objekt, så bygg ut metoden så att den också anropar sin förälders toString-metod, så att vi får något som liknar det här:

markuss@objekt$ java Test < test.txt får+VB (TokenTag@de6ced) får+NN (TokenTag@c17164) får+NN (TokenTag@1fb8ee3) nej+IJ (TokenTag@61de33) får+NN (TokenTag@14318bb) får+VB (TokenTag@ca0b6) inte+NEG (TokenTag@10b30a7) får+NN (TokenTag@1a758cb) får+NN (TokenTag@1b67f74) får+VB (TokenTag@69b332) lamm+NN (TokenTag@173a10f) markuss@objekt$

Uppgift 2

Bygg ut testklassen så att de taggade orden inte bara skrivs ut, utan även lagras i en HashMap. Associera varje ord med en Integer, så har vi möjligheten att räkna frekvenser på dem! När du lagrar ett taggat ord i hashtabellen behöver du först kontrollera ifall den redan finns, gör den det ska den läggas till med sitt gamla värde plus 1, finns den inte ska den läggas till med värdet 1.

Efter att du lagrat alla taggade ord i din hashtabell ska du löpa igenom nycklarna (använd keySet()), och skriva ut alla lagrade nycklar och deras associerade värde. Du borde se något som liknar det här:

markuss@objekt$ java Test < test.txt får+VB (TokenTag@de6ced) får+NN (TokenTag@c17164) får+NN (TokenTag@1fb8ee3) nej+IJ (TokenTag@61de33) får+NN (TokenTag@14318bb) får+VB (TokenTag@ca0b6) inte+NEG (TokenTag@10b30a7) får+NN (TokenTag@1a758cb) får+NN (TokenTag@1b67f74) får+VB (TokenTag@69b332) lamm+NN (TokenTag@173a10f) Frequencies and keys 1 får+NN (TokenTag@1b67f74) 1 får+NN (TokenTag@1fb8ee3) 1 får+NN (TokenTag@c17164) 1 inte+NEG (TokenTag@10b30a7) 1 får+VB (TokenTag@de6ced) 1 nej+IJ (TokenTag@61de33) 1 får+NN (TokenTag@1a758cb) 1 får+VB (TokenTag@ca0b6) 1 lamm+NN (TokenTag@173a10f) 1 får+VB (TokenTag@69b332) 1 får+NN (TokenTag@14318bb) markuss@objekt$

Det här är inte riktigt vad vi hade tänkt oss... det verkar som om unika objekt blir unika nycklar, men vi kan ju ha flera objekt som representerar samma taggade ord...

Uppgift 3

Implementera metoderna int hashCode() och boolean equals(Object o) i klassen TokenTag. Du vet att du har lyckats när unika taggade ord blir unika nycklar!

markuss@objekt$ java Test < test.txt får+VB (TokenTag@1a5bf) får+NN (TokenTag@1a4d3) får+NN (TokenTag@1a4d3) nej+IJ (TokenTag@1b2b4) får+NN (TokenTag@1a4d3) får+VB (TokenTag@1a5bf) inte+NEG (TokenTag@3293c6) får+NN (TokenTag@1a4d3) får+NN (TokenTag@1a4d3) får+VB (TokenTag@1a5bf) lamm+NN (TokenTag@329b95) Frequencies and keys 1 nej+IJ (TokenTag@1b2b4) 1 inte+NEG (TokenTag@3293c6) 3 får+VB (TokenTag@1a5bf) 1 lamm+NN (TokenTag@329b95) 5 får+NN (TokenTag@1a4d3) markuss@objekt$

Uppgift 4

Skriv om testklassen så att den inte längre använder en HashMap, utan en TreeMap. När du kör den direkt efter omvandlingen kommer du att få ett felmeddelande:

markuss@objekt$ java Test < test.txt får+VB (TokenTag@1a5bf) Exception in thread "main" java.lang.ClassCastException: TokenTag cannot be cast to java.lang.Comparable at java.util.TreeMap.getEntry(TreeMap.java:325) at java.util.TreeMap.containsKey(TreeMap.java:209) at Test.main(Test.java:9) markuss@objekt$

Det är Javas sätt att berätta för dig att bara jämförbara nycklar går att lagra i en TreeMap. Lösningen är att låta TokenTag implementera gränssnittet Comparable<TokenTag>. Du gör detta genom att deklarera att klassen implementerar gränssnittet, samt implementera metoden int compareTo(TokenTag tt). En lämplig implementation av den metoden är att i första hand jämföra attributet token, och i andra hand attributet tag.

Återigen märks det att du lyckats genom att programmet beter sig som förut, fast med skilnaden att nycklarna är sorterade:

markuss@objekt$ java Test < test.txt får+VB (TokenTag@1a5bf) får+NN (TokenTag@1a4d3) får+NN (TokenTag@1a4d3) nej+IJ (TokenTag@1b2b4) får+NN (TokenTag@1a4d3) får+VB (TokenTag@1a5bf) inte+NEG (TokenTag@3293c6) får+NN (TokenTag@1a4d3) får+NN (TokenTag@1a4d3) får+VB (TokenTag@1a5bf) lamm+NN (TokenTag@329b95) Frequencies and keys 5 får+NN (TokenTag@1a4d3) 3 får+VB (TokenTag@1a5bf) 1 inte+NEG (TokenTag@3293c6) 1 lamm+NN (TokenTag@329b95) 1 nej+IJ (TokenTag@1b2b4) markuss@objekt$

Uppgift 5

Skriv om metoden compareTo, så att den i första hand jämför taggarna, och i andra hand orden. Teoretisera kring vad du tror kommer att skilja körningen från den ovan innan du testar själv.