user2709168
user2709168

Reputation: 117

Hashmap not receiving expected value

Sorry if this is a dumb question, I'm very new to working with maps.

static void redacted(Map<List<String>, List<String>> whatComesNext, List<String> text) {
    List<String> maurice = new ArrayList<String>(); //feeds the double string key to the map whatComesNext
    List<String> masterHash = new ArrayList<String>(); //keeps track of the first two non "<START>" keys
    List <String> bryan = new ArrayList<String>(); //returns a double value to the map when masterhash appears
    masterHash.add(text.get(2)); //adds third element of the list to masterHash
    masterHash.add(text.get(3)); //adds fourth element to masterHash
    for (int i=0; i<=text.size()-3; i++) {
      maurice.clear();
      maurice.add(text.get(i)); //gets nth element of the list and adds to maurice 
      maurice.add(text.get(i+1)); //gets element following the nth one
      if (maurice.equals(masterHash)) { //assigns two strings to masterHash key instead of one
        bryan.add(text.get(i+2));
        bryan.add(text.get(i+3));
        whatComesNext.put(masterHash, bryan);
      }
      else {
        whatComesNext.put(maurice, Arrays.asList(text.get(i+2)));
      }
    }
  }

The purpose is to assemble a given empty map, whatComesNext, with a specific set of keys and values according to the provided String List "text". Each key will be a String list containing a pair of words from text. For example, given a list of 7 elements, the keys would be a list containing element [0] and element [1], element [1] and element [2], etc., until the final key contains elements [5] and [6].

The value assigned to each key will be the element in text immediately following the two Strings in the key. For example, the key <0 1> would have the value <2>. If you had the string list "Hello there StackOverflow, I need your help." (where you separated the string with .split(" ")) the hashmap would be

[Hello/there, StackOverflow]

[there/StackOverflow,, I]

[StackOverflow,/I, need]

[I/need, your]

[need/your, help.]

Where the slashes represent a String list containing of two elements, the string before and after the slash.

The slight catch here though is that every String list "text" can be assumed to have their first two elements as "" and their final element as "". These are still treated as regular keys and values (so a hash pair of [/Hello, StackOverflow] is plausible) the first key that doesn't contain "" must have a value list of the following two strings.

Hopefully I haven't lost you yet. Here's the code that tests what I have in mind:

List<String> prisoner =
        Arrays.asList("<START> <START> I am not a number. I am a free man! <END>".split(" "));
    Map<List<String>, List<String>> whatComesNext = new LinkedHashMap<>();
    MarkovText.learnFromText(whatComesNext, prisoner);
    System.out.println(whatComesNext);
    assertEquals(10, whatComesNext.size());
    assertEquals(Arrays.asList("not", "a"), 
        whatComesNext.get(Arrays.asList("I", "am")));
    assertEquals(Arrays.asList("free"), 
        whatComesNext.get(Arrays.asList("am", "a")));
    assertEquals(Arrays.asList("<END>"), 
        whatComesNext.get(Arrays.asList("free","man!")));

For this, I think everything works except for the fact that somehow I return the next four elements following my "masterHash" key instead of the next two.

EDIT: I also need to mention that if the key containing the first two non "" strings is overwritten later in the loop (if those strings appear again in the same order), then the overwritten value list still contains the following two strings.

Upvotes: 0

Views: 179

Answers (1)

xiaofeng.li
xiaofeng.li

Reputation: 8587

One big problem with your code is that you are changing the state of a map key, which you should never do after you put that key into the map. The contract is broken and it affects every operation with the map.

You should create a new key object for each pair of words. A much better option is to use immutable objects as map keys.

Upvotes: 2

Related Questions