简体   繁体   中英

Incorrect mapping values when using LinkedHashMap to a List

I am to initialize what is called an LZWDictionary to have an initial set of entries taken from the set of unique characters in a provided string.

Unique characters are added to a map as they are encountered in the provided input string, with an increasing index value (beginning at index 0). At the same time, the characters are added to a list. The indices associated with each dictionary entry in the map thus relate to their index (position) in the list.

Here is the code that I tried with comments on my thought process.

// Initialising map
map = new LinkedHashMap<>();
// Initialising list
list = new ArrayList<>();
// Declaring String variable for holding character
String str;
// Declaring index variable for holding Value
int index;

// If block for checking empty string.
if (characters.length() == 0)
    // Throwing IllegealArgumentException if String is empty.
    throw new IllegalArgumentException("Input should not be empty!!!");
else {

    // Iterating over the String
    for (int i = 0; i < characters.length(); i++) {
        // Taking particular character in the Iteration
        str = "" + characters.charAt(i);
        // Checking value of a particular character in the map
        if (map.get(str) == null) {

            // If not present in map, then add that to the map and list
            map.put(str, 1);
            list.add(str);
        }

        else {

            index = map.get(str);
            map.replace(str, index + 1);
        }

    }
}

I am getting a java.lang.AssertionError where the index value for "a" is not correct in map expected<0> but was <5>. The sample code is:

LZWDictionary act = new LZWDictionary("ababababa");
List<String> exp = Arrays.asList("a","b");

This part of your code isn't at all what you described:

if (map.get(str) == null) {

    // If not present in map, then add that to the map and list
    map.put(str, 1);
    list.add(str);
}

else {

    index = map.get(str);
    map.replace(str, index + 1);
}

You expect input "ababababa" to return a list [a, b] , ie the unique characters, and a map with {a: 0, b: 1} , right? And input "aaaabbbbbbbbbbbb" should give the same result, right?

So the result list and result maps are only updated the first time a characters is seen, right?

Which means your code above shouldn't have an else clause. Get rid of it.

Also, the map is supposed to have the index of the unique character. But you have map.put(str, 1) . They can't all be at index 1, can they?

Re-think what you're doing.

EDITED @20191105: simplified the code by removing additional 'int' variable as suggested by @Andreas


So, the problem of your code is the duplicated handling of same input character (In case you only want to count the first encountered appearance).

Then as mentioned by @Andreas, the code should be changed as below for getting what you've described:

    // Declaring index variable for holding Value
    //int index = 0;

.

        // Iterating over the String
        for (int i = 0; i < characters.length(); i++) {
            // Taking particular character in the Iteration
            str = "" + characters.charAt(i);
            // Checking value of a particular character in the map

            /*
             * if (map.get(str) == null) {
             * 
             * // If not present in map, then add that to the map and list map.put(str, 1);
             * list.add(str); }
             * 
             * else {
             * 
             * index = map.get(str); map.replace(str, index + 1); }
             */
            // If not present in map, then add that to the map and list map.put(str, 1);
            if (map.get(str) == null) {
                //map.put(str, index++);
                map.put(str, map.size());
                list.add(str);
            }
        }

    // Below is just for testing what has been put to the collections ... 
    Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator();
    while (it.hasNext()) {
        Entry<String, Integer> e = it.next();
        System.out.println(e.getKey() + " ; " + e.getValue());
    }

    for (String a: list) {
        System.out.println(a);
    }

If you want is a list of the distinct characters of your input String, you will want to use a Set :

Set<Character> uniqueCharacters = new HashSet<>();
for (char c : characters.toCharArray()) {
    uniqueCharacters.add(c);
}
// at this point uniqueCharacters only contains [a, b] with your sample input.

You can try it here .

However, if you need to maintain a map, it might as well be the only collection you maintain: its set of keys accessible through Map.keySet() will already contain the set of unique characters of the String since you won't create entries for non-existant characters:

Map<Character, Integer> charsAndExtraInfo = new HashMap<>();
for (char c : characters.toCharArray()) {
    charsAndExtraInfo.put(c, whatever);
}
// at this point charsAndExtraInfo.keySet() only contains [a, b] with your sample input

You can try it here (with a char count sample).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM