Wednesday, 19 September 2012

Puzzle 60: One-Liners

Puzzle 60: One-Liners

Now it's your turn to write some code. Each of the following puzzles can be solved with a method whose body contains but a single line. On your mark, get set, code!
  1. Write a method that takes a List of elements and returns a new List containing the same elements in the same order with the second and subsequent occurrences of any duplicate elements removed. For example, if you pass in a list containing "spam", "sausage", "spam", "spam", "bacon", "spam", "tomato", and "spam", you'll get back a new list containing "spam", "sausage", "bacon", and "tomato".
  2. Write a method that takes a string containing zero or more tokens separated by commas and returns an array of strings representing the tokens in the order they occur in the input string. Each comma may be followed by zero or more white space characters, which must be ignored by the method. For example, if you pass the string "fear, surprise, ruthless efficiency, an almost fanatical devotion to the Pope, nice red uniforms", you'll get back a five-element string array containing "fear", "surprise", "ruthless efficiency", "an almost fanatical devotion to the Pope", and "nice red uniforms".
  3. Suppose that you have a multidimensional array that you want to print for debugging purposes. You don't know how many levels the array has or what type of objects are stored at each level in the array. Write a method that shows you all the elements at each level.
  4. Write a method that takes two int values and returns TRue if the first value has more bits set than the second in its two's-complement binary representation.

Solution 60: One-Liners

  1. It is well known that you can eliminate all the duplicate elements in a collection by putting its contents into a Set. In this puzzle, you were also asked to preserve the order of the original collection. Luckily, there is a Set implementation that maintains its elements in insertion order, and it offers near-HashMap performance to boot. It's called LinkedHashSet, and it was added to the platform in release 1.4. Internally, it is implemented as a hash table with a linked list running through it. There is also a map version that you can use to make custom caches. Once you know about LinkedHashSet, it's easy to solve this puzzle. The only other wrinkle is that you were asked to return a List, so you have to initialize a List with the contents of the LinkedHashSet. Putting it all together, here is the solution:
    static <E> List<E> withoutDuplicates(List<E> original) {
    
        return new ArrayList<E>(new LinkedHashSet<E>(original));
    
    }
    
    
  2. When it comes to parsing a string into tokens, many programmers' thoughts turn immediately to StringTokenizer. This is most unfortunate, as StringTokenizer became obsolete as of release 1.4, when regular expressions were added to the platform (java.util.regex). If you tried to solve this puzzle with StringTokenizer, you quickly realized that it isn't a very good fit. With regular expressions, it's a snap. To solve this puzzle in one line, use the convenience method String.split, which takes a regular expression describing the token delimiter. If you haven't used regular expressions before, they may look a bit cryptic, but they're amazingly powerful and well worth learning:
    static String[] parse(String string) {
    
        return string.split(",\\s*");
    
    }
    
    
  3. This is a trick question. You don't even have to write a method. The method is provided for you in release 5.0 and later releases, and is called Arrays.deepToString. If you pass it an array of object references, it returns a nice string representation. It can deal with nested arrays and even circular references, where an array element refers to the enclosing array, directly or indirectly. In fact, the Arrays class in release 5.0 provides a whole family of toString, equals, and hashCode methods that allow you to print, compare, or hash the contents of any array of primitives or object references.
  4. In order to solve this puzzle in one line, you need to know that a whole family of bit-twiddling methods were added to the platform in release 5.0. The wrapper classes for the integral types (Integer, Long, Short, Byte, and Char) now support common bit-manipulation operations, including highestOneBit, lowestOneBit, numberOfLeadingZeros, numberOfTrailingZeros, bitCount, rotateLeft, rotateRight, reverse, signum, and reverseBytes. In this case, what you need is Integer.bitCount, which returns the number of set bits in an int value:
    static boolean hasMoreBitsSet(int i, int j) {
    
        return (Integer.bitCount(i) > Integer.bitCount(j));
    
    }
    
    
In summary, each major release of the Java platform has a few new "hidden treasures" in the libraries. All four parts of this puzzle relied on such treasures. Each time a new release of the platform comes out, you should study the new features and enhancements page so you don't miss out on any of the goodies that the release has to offer [Features-1.4, Features-5.0]. Knowing what's in the libraries can save you lots of time and effort and can enhance the speed and quality of your programs.

No comments:

Post a Comment

Your comments are welcome!