Does collection Extend list?

Simple Examples of Using Collection Class In this section we will illustrate a few interesting uses of collection classes, focussing on how they are combined to represent and process complex information easily. During this discussion, we will examine a useful notation for describing the interrelated collections needed to specify these data structures. We call this modeling the data structure by collection classes.

For a first task, assume that we want to store the antonym [singular] and synonyms [plural] for a large collection of words. Each word will have a single best antonym and an arbitrary number of synonyms. Given a word, we want to be able to retrieve its antonym and synonyms quickly and easily. So, we will model the data structure by first using a map from a word [a String] to its antonym/synonym information. We start by writing Map[String] -> antonym-synonyms-value. Next, we will refine this description by representing the value associated with a word by using a list: its first position stores the antonym [a String] and its second position stores all the synonmyms; we now write model as Map[String] -> List[String,synonyms]. Finally, we will refine this model by representing all of the synonyms in a set of Strings; we write this last refinement as Map[String] -> List[String,Set[String]]. We read this model as a map from a String to a two element list, whose first element is a String and whose second element is a set of Strings.

Before proceeding, we should note that this is not the only way to model this data. We could also use Map[String] -> List[String,List[String*]]. Here we model all the synonyms as a list, not a set; the word String and the superscript star indicates that every position in the list is a String and that there are zero or more of them [alot like braces in EBNF]. So, which is better to model this aspect of the data, a set or a list? It depends whether the synonyms have any sequential properties: are they ordered [would they need to be inserted in order; would removing one need to retain the order]? is there some logical notion of one synonym following another? I answered these questions no, so I chose the simpler set collection to model this aspect of the problem. If I needed to print the synonyms in order, I could always copy the set into a temporary list and then sort the list.

As a first task, let's assume that we have already built this map, called thesaurus. Now, let's do a simple operation on it: lets choose a word, look up its antonym, and then look up and print all the synoynms of its antonym [this is why we don't have to store more than one antonym: because we can store it as a word in the data structure, along with its synonyms]. So, if we choose the word big, we might retrieve the antonym small, and then retrieve its synonyms little, tiny, short, and minute. The code for doing this is shown below. Recall that collection classes all use Object, so we must cast the results [using interface names] frequently.

String toCheck = Prompt.forString["Enter word to check"]; List checkInfo = [List]thesaurus.get[toCheck]; if [checkInfo != null] { //is word in the map? String antonym = [String]checkInfo.get[0]; //antonym at index 0 List antInfo = [List]thesaurus.get[antonym]; if [antInfo != null] { //is antonym in the map? Set synOfAnt = [Set]antInfo.get[1]; //synonyms at index 1 System.out.println["Antonyms of " + toCheck + " = " + antonym + " and " + synOfAnt];} } All the get operations are O[1], so this sequence of operations is also O[1]: everything is very efficient. If we knew that all the words were in the data structure, we could pack everything into one large nested/cascaded method call. String toCheck = Prompt.forString["Enter word to check"]; String antonym = [[List]thesaurus.get[toCheck]].get[0]; Set synOfAnt = [Set][ [[List]thesaurus.get[antonym]].get[1]]; System.out.println["Antonyms of " + toCheck + " = " + antonym + " and " + synOfAnt];

Actually, we could just define Object synOfAnt = [[List]thesaurus.get[antonym]].get[1]; because all we are doing with this object is catentating it, so Java will automatically call its toString method, which all objects have. The principle is not to cast unless it is really necessary for subsequent operations.

Now, let's write some more complicated code: the code to build this data structure. Lets start with a method that takes a String of tokens representing a word, followed by its antonym [there must be one], followed by any number of synonyms [including zero]. This method will build a new entry and put it in the map [so it must be called repeatedly to build all the entries in thesaurus].

void addTo[String entry, Map thesaurus] { //Get word and anytonym String word,antonym; //must declare outside try, to use after StringTokenizer st = new StringTokenizer[entry]; try { word = st.next[]; antonym = st.next[]; }catch [NoSuchElementException e] {throw new IllegalArgumentException ["addTo: too few words in " + entry];} //Get synonyms in set Set synonyms = new HashSet[]; for [; st.hasNextToken[]; ] synonyms.add[st.nextToken[]]; //Extend thesaurus List wordInfo = new ArrayList[]; wordInfo.add[antonym]; //or, wordInfo.set[0,antonym]; wordInfo.add[synonyms]; //or, wordInfo.set[1,synonyms]; thesaurus.put[word, wordInfo]; }This method builds the entries inside out: first it gets the key and antonym, then it constructs the set of synonyms, then it constructs the 2-element list of the antonym and synonym set, finally it adds the word and its associated information to the map. On a different dimension, I put the whole method boyd in the try-catch, which I also could have done above.

We could write a different but equivalent version that builds entries outside in.

void addTo[String entry, Map thesaurus] { try { //Get word and anytonym StringTokenizer st = new StringTokenizer[entry]; String word = st.next[]; String antonym = st.next[]; //Extend thesaurus List wordInfo = new ArrayList[]; thesaurus.put[word, wordInfo]; //Fill in list with antonym/synonym set wordInfo.add[antonym]; Set synonyms = new HashSet[]; wordInfo.add[synonyms]; for [; st.hasNextToken[]; ] synonyms.add[st.nextToken[]]; }catch [NoSuchElementException e] {throw new IllegalArgumentException ["addTo: too few words in " + entry];} }This method again first gets the key and antonym [to ensure a legal entry], then it constructs an empty list and adds the key/list to the map, then it fills in the list with the antonym and an empty set for the synonyms, finally it adds each synonym to the set. Because the objects stored in the value of part of the map are shared by local variables inside this method, they can be mutated AFTER they have been added. Remember not to mutate keys in a map; if you must change them, remove the entry, then mutate the key, then re-add the entry.

Video liên quan

Chủ Đề