Exercism v3 launches on Sept 1st 2021. Learn more! ๐Ÿš€๐Ÿš€๐Ÿš€
Avatar of rootulp

rootulp's solution

to Hexadecimal in the Java Track

Published at Jul 13 2018 · 4 comments
Instructions
Test suite
Solution

Note:

This solution was written on an old version of Exercism. The tests below might not correspond to the solution code, and the exercise may have changed since this code was written.

Convert a hexadecimal number, represented as a string (e.g. "10af8c"), to its decimal equivalent using first principles (i.e. no, you may not use built-in or external libraries to accomplish the conversion).

On the web we use hexadecimal to represent colors, e.g. green: 008000, teal: 008080, navy: 000080).

The program should handle invalid hexadecimal strings.

Running the tests

You can run all the tests for an exercise by entering

$ gradle test

in your terminal.

Source

All of Computer Science http://www.wolframalpha.com/examples/NumberBases.html

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

HexadecimalTest.java

import org.junit.Test;
import org.junit.Ignore;
import static org.junit.Assert.assertEquals;

public class HexadecimalTest {


    @Test
    public void testOne(){
        int expected = 1;
        assertEquals(expected, Hexadecimal.toDecimal("1"));
    }

    @Ignore
    @Test
    public void testC(){
        int expected = 12;
        assertEquals(expected, Hexadecimal.toDecimal("c"));
    }

    @Ignore
    @Test
    public void test10(){
        int expected = 16;
        assertEquals(expected, Hexadecimal.toDecimal("10"));
    }

    @Ignore
    @Test
    public void testAf(){
        int expected = 175;
        assertEquals(expected, Hexadecimal.toDecimal("af"));
    }

    @Ignore
    @Test
    public void test100(){
        int expected = 256;
        assertEquals(expected, Hexadecimal.toDecimal("100"));
    }

    @Ignore
    @Test
    public void test19ace(){
        int expected = 105166;
        assertEquals(expected, Hexadecimal.toDecimal("19ace"));
    }

    @Ignore
    @Test
    public void testInvalid(){
        int expected = 0;
        assertEquals(expected, Hexadecimal.toDecimal("carrot"));
    }

    @Ignore
    @Test
    public void testBlack(){
        int expected = 0;
        assertEquals(expected, Hexadecimal.toDecimal("000000"));
    }

    @Ignore
    @Test
    public void testWhite(){
        int expected = 16777215;
        assertEquals(expected, Hexadecimal.toDecimal("ffffff"));
    }

    @Ignore
    @Test
    public void testYellow(){
        int expected = 16776960;
        assertEquals(expected, Hexadecimal.toDecimal("ffff00"));
    }
}
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Hexadecimal {

  private static final Map<Character, Integer> HEX_MAP = hexMap();
  private static final Set<Character> VALID_CHARACTERS = HEX_MAP.keySet();

  private static Map<Character, Integer> hexMap() {
    Map<Character, Integer> hexMap = new HashMap<>();
    hexMap.put('0', 0);
    hexMap.put('1', 1);
    hexMap.put('2', 2);
    hexMap.put('3', 3);
    hexMap.put('4', 4);
    hexMap.put('5', 5);
    hexMap.put('6', 6);
    hexMap.put('7', 7);
    hexMap.put('8', 8);
    hexMap.put('9', 9);
    hexMap.put('a', 10);
    hexMap.put('b', 11);
    hexMap.put('c', 12);
    hexMap.put('d', 13);
    hexMap.put('e', 14);
    hexMap.put('f', 15);
    return hexMap;
  }

  public static int toDecimal(String str) {
    if (!valid(str)) {
      return 0;
    }
    return calculateDecimal(str);
  }

  private static int calculateDecimal(String str) {
    int decimal = 0;
    for (int i = 0; i < str.length(); i++) {
      int multiplier = multiplier(i, str.length());
      int digit =  digitToDecimal(str.charAt(i));
      decimal += digit * multiplier;
    }
    return decimal;
  }

  private static int multiplier(int index, int strLength) {
    return (int) Math.pow(16, (strLength - 1 - index));
  }

  private static int digitToDecimal(Character digit) {
    return HEX_MAP.get(digit);
  }

  private static boolean valid(String str) {
    for (Character c : str.toCharArray()) {
      if (!VALID_CHARACTERS.contains(c)) {
        return false;
      }
    }
    return true;
  }
}

Community comments

Find this solution interesting? Ask the author a question to learn more.
Avatar of jaebradley

Can you think of an implementation that wouldn't use a Map?

Avatar of jaebradley

valid iterates through the input String once. Then you iterate through the input String again in calculateDecimal. Can you think of a way to incorporate your validation logic such that you only have to iterate through the input String only once?

Avatar of jaebradley

why have multiplier and digitToDecimal (especially the latter)?

Avatar of jaebradley

There's not really a need for VALID_CHARACTERS. I think it's perfectly readable to do something like HEX_MAP.keySet().contains() instead.

What can you learn from this solution?

A huge amount can be learned from reading other peopleโ€™s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?