1

I am doing the following coding challenge in java:

/**
     * 4. Given a word, compute the scrabble score for that word.
     * 
     * --Letter Values-- Letter Value A, E, I, O, U, L, N, R, S, T = 1; D, G = 2; B,
     * C, M, P = 3; F, H, V, W, Y = 4; K = 5; J, X = 8; Q, Z = 10; Examples
     * "cabbage" should be scored as worth 14 points:
     * 
     * 3 points for C, 1 point for A, twice 3 points for B, twice 2 points for G, 1
     * point for E And to total:
     * 
     * 3 + 2*1 + 2*3 + 2 + 1 = 3 + 2 + 6 + 3 = 5 + 9 = 14
     * 
     * @param string
     * @return
     */

My idea is to insert all these letters in a hash map by doing something like this:

map.add({A,,E,I,O,U,L,N,R,S,T}, 1);

Is there any way to do this in java?

5
  • Sure. map.put('A', 1); map.put('E', 1); etc. Or just use a loop over the array of keys. Commented Mar 3, 2018 at 16:43
  • so I can't do this in one statement. Commented Mar 3, 2018 at 16:43
  • Yes, you can, using the stream api, or List.forEach for example. Commented Mar 3, 2018 at 16:45
  • 1
    Note that putting collections as keys is very inefficient since hash computation needs to be done often which requires to iterate the whole collection of the key over and over. Of course you can counter this with a custom collection that caches its hash value or with IdentityHashMaps that ignore the hash values of the collection and instead only compare the identity. Commented Mar 3, 2018 at 16:56
  • "What I am actually looking for is an statement in which I can store all these letters with the same value in a hash_map." So you should mention that in the question. If you want a single statement, say so. Although that may not be a great thing to ask for. Commented Mar 3, 2018 at 16:59

5 Answers 5

4

You said in your comments that you would like to be able to add all these entries in a single statement. While Java is not a great language for doing things like this in a single statement, it can be done if you are really determined to do so. For example:

Map<Character, Integer> scores =
    Stream.of("AEIOULNRST=1","DG=2","BCMP=3","FHVWY=4" /* etc */ )
        .flatMap(line -> line.split("=")[0].chars().mapToObj(c -> new Pair<>((char)c, Integer.parseInt(line.split("=")[1]))))
        .collect(Collectors.toMap(Pair::getKey, Pair::getValue));

System.out.println("C = " + scores.get('C'));

Output:

C = 3

In the code above, I first build a stream of all the entries (as Pairs), and collect them into a map.

Note:

The Pair class I have used above is from javafx.util.Pair. However you could just as easily use AbstractMap.SimpleEntry, your own Pair class, or any collection data type capable of holding two Objects.


A Better Approach

Another idea would be to write your own helper method. This method could be put into a class which contains similar helper methods. This approach would be more idiomatic, easier to read, and thus easier to maintain.

public enum MapHelper {
; // Utility class for working with maps
public static <K,V> void multiKeyPut(Map<? super K,? super V> map, K[] keys, V value) {
for(K key : keys) {
    map.put(key, value);
}}}

Then you would use it like this:

Map<Character, Integer> scores = new HashMap<>();
MapHelper.multiKeyPut(scores, new Character[]{'A','E','I','O','U','L','N','R','S','T'}, 1);
MapHelper.multiKeyPut(scores, new Character[]{'D','G'}, 2);
MapHelper.multiKeyPut(scores, new Character[]{'B','C','M','P'}, 3);
/* etc */
Sign up to request clarification or add additional context in comments.

1 Comment

@patzi I've updated my answer with a more idiomatic approach. Have another look.
1

Take an array of length 26, each element representing an alphabet's score. So, we will have an array like this:-

alphabetScore = [1,3,3,2,.....................];

Now, iterate over the word, and keep adding the score of the current alphabet in the total score.

4 Comments

I don't see how this answer has anything to do with the question, how to insert same value to a map multiple times with different keys...?
Because this question might be an X/Y problem. I would personally favor this approach over a HashMap.
This approach is more efficient but more prone to error I think. I may misplace some number;
it’s not necessarily error-prone: just use the char literal, both when initializing and when accessing.
0

Map has no methods that operate on multiple keys, but you could stream a list of these characters and call forEach:

Map<Character, Integer> scores = new HashMap<>();
Stream.of('A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T')
      .forEach(c -> scores.put(c, 1));
Stream.of('D', 'G').forEach(c -> scores.put(c, 2));
// etc...

1 Comment

forEach(scores::put) could, in theory, result in concurrency issues. In general you should be wary of streams with side-effects. Instead, build a stream of all the entries and collect them into a map.
0

I think it's not a good idea to store list of more characters as keys (take a look at this question) and single value corresponding to this key, but if you really need that, you might want to give a try to this:

Map<ArrayList<Character>, Integer> map = new HashMap<>();
map.put(new ArrayList<Character>(Arrays.asList('A', 'E',...)), 1);
map.put(new ArrayList<Character>(Arrays.asList('D', 'G',...)), 2);

Personally, I would suggest using HashMap<Integer, ArrayList<Character>> - keys are "values" of a set of letters (e. g. key would be 1 for ArrayList containg letters: A, E, etc.), as a value corresponding to that Integer key could be ArrayList storing characters (A, E,...). You can achieve that result with:

Map<Integer, ArrayList<Character>> map = new HashMap<>();
map.put(1, new ArrayList<Character>(Arrays.asList('A', 'E',...)));
map.put(2, new ArrayList<Character>(Arrays.asList('D', 'G',...)));

14 Comments

In your example, how would one retrieve the letter score for a single letter?
What I am actually looking for is an statement in which I can store all these letters with the same value in a hash_map.
for (Map.Entry<ArrayList<Character>, Integer> entry : map.entrySet()) { if (entry.getKey().contains('a')) { int value = entry.getValue(); break;}}
Note that putting collections as keys is very inefficient since hash computation needs to be done often which requires to iterate the whole collection of the key over and over. Of course you can counter this with a custom collection that caches its hash value or with IdentityHashMaps that ignore the hash values of the collection and instead only compare the identity.
@Zabuza I understand it's a bad idea, I would suggest OP to use "value" of a letter as a key, and list of letters could be stored as values to the corresonding Integer key. I was giving him a possibility how he could achieve that.
|
0

One line:

Map<String, Integer> map = Stream.of( "A", "E", "I", "O", "U", "L", "N", "R", "S", "T" ).collect( Collectors.toMap( Function.identity(), o -> 1 ) );

Or if you already have a list of strings

Collection<String> chars = new ArrayList<>();
// Add to collection
Map<String, Integer> map = chars.stream().collect( Collectors.toMap( Function.identity(), o -> 1 ) );

You can use the same method to add other keys with the same value

map.addAll( Stream.of( "F", "H", "V", "W", "Y" ).collect( Collectors.toMap( FUnction.identity(), o -> 4 );

Ultimately, it would be best to use a helper function for readability

private Map<String, Integer> mapScores( int score, String... letter ) {
    return Stream.of( letter ).collect( Collectors.toMap( Function.identity(), o -> score ) );
}

Map<String, Integer> map = new ConcurrentHashMap<>();
map.putAll( mapScores( 1, "A", "E", "I", "O", "U", "L", "N", "R", "S", "T" ) );
map.putAll( mapScores( 2, "D", "G" ) );
map.putAll( mapScores( 3, "B", "C", "M", "P" ) );
map.putAll( mapScores( 4, "F", "H", "V", "W", "Y" ) );
map.put( "K", 5 );
map.putAll( mapScores( 8, "J", "X" ) );
map.putAll( mapScores( 10, "Q", "Z" ) );

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.