15a: Sets, Maps, and Comparable

ICS211, Spring 2013
Dr. Zach

(switch view)

Status check

Set

Set Implementations

Set Uses

Set Variations

Map

Map Methods

Map Implementations


Map Uses: Counting instances

  /** Counts the frequency of every token in a given file. */
  Scanner filein = new Scanner(new java.io.File(filename));
  Map<String, Integer> wordCounts = new HashMap<String, Integer>();
  while (filein.hasNext()) {
    String word = filein.next().toLowerCase();
    if (wordCounts.containsKey(word)) {
      wordCounts.put(word, wordCounts.get(word) + 1);
    }else {
      wordCounts.put(word, 1);
    }
  }

A sample input file

How much wood would a woodchuck chuck
  if a woodchuck could chuck wood ?
A woodchuck would chuck all the wood he could chuck
  if a woodchuck could chuck wood .

A woodchuck, aka groundhog

Map Uses: Printing with toString()

  System.out.println(wordCounts);

Prints:

{wood=4, how=1, chuck=5, a=4, woodchuck=4, he=1, the=1, .=1, much=1, 
 would=2, could=3, if=2, ?=1, all=1}

Change HashMap to LinkedHashMap:

{how=1, much=1, wood=4, would=2, a=4, woodchuck=4, chuck=5, if=2, could=3, ?=1, 
  all=1, the=1, he=1, .=1}

Map Uses: Querying

  System.out.println("wood: " + wordCounts.get("wood"));
  System.out.println("chuck: " + wordCounts.get("chuck"));
  System.out.println("woodchuck: " + wordCounts.get("woodchuck"));

Prints:

wood: 4
chuck: 5
woodchuck: 4

Map Uses: Iterating over contents

  for (String word : wordCounts.keySet()) {
    System.out.println(word + " " + wordCounts.get(word));
  }

Prints:

wood 4
how 1
chuck 5
a 4
woodchuck 4
he 1
the 1
. 1
much 1
would 2
could 3
if 2
? 1
all 1

Map Uses: Iterating over contents with Entry set

  for (Map.Entry<String, Integer> wordCount : wordCounts.entrySet()) {
    System.out.println(wordCount.getKey() + " " + wordCount.getValue());
  }

Prints same as previous slide.

Map Uses: Views

  //removes all entries (keys and count values) for punctuation
  Set<String> punctuation = new HashSet<String>(Arrays.asList(".", "?", "!"));
  wordCounts.keySet().removeAll(punctuation);
  System.out.println(wordCounts);
  //removes all entries with a count value of 1, 2, or 3
  Set<Integer> counts = new HashSet<Integer>(Arrays.asList(1, 2, 3));
  wordCounts.values().removeAll(counts);
  System.out.println(wordCounts);  //Prints: {wood=4, chuck=5, a=4, woodchuck=4}

Another view example

  String[] nums = {"one", "two", "three", "four"};
  System.out.println(java.util.Arrays.toString(nums));  //[one, two, three, four]

  List<String> numbers = java.util.Arrays.asList(nums);
  numbers.set(1, "2");

  System.out.println(java.util.Arrays.toString(nums));  //[one, 2, three, four]

Comparator

PlayingCard

public class PlayingCard {

  private int value;
  private Suit suit;

  public PlayingCard(int value, Suit suit) {
    if (value < 1 || value > 13) {
      throw new IllegalArgumentException("Value " + value +
          " out of valid 1 - 13 range.");
    }
    this.value = value;
    this.suit = suit;
  }

  public int getValue() {
    return this.value;
  }
  public Suit getSuit()  {
    return this.suit;
  }
  
  @Override
  public String toString() {
    String v = "" + this.value;
    switch (this.value) {
      case 1:  v = "A"; break;
      case 11: v = "J"; break;
      case 12: v = "Q"; break;
      case 13: v = "K"; break;
    }
    return v + this.suit;
  }

  // nested class for Suit
  public static enum Suit {
    C, D, H, S;
  }
}

PlayingCard Comparator

PlayingCard Comparator Use

  List<PlayingCard> deck = new ArrayList<PlayingCard>(52);
  for (int v = 1; v <= 13; v++) {
    for (PlayingCard.Suit s : PlayingCard.Suit.values()) {
      deck.add(new PlayingCard(v, s));
    }
  }
  System.out.println(deck);
  Collections.shuffle(deck);
  System.out.println(deck);
  Collections.sort(deck, new BySuitThenValue());  //Comparator use
  System.out.println(deck);

Prints:

[AC, AD, AH, AS, 2C, 2D, 2H, 2S, 3C, 3D, 3H, 3S, 4C, 4D, 4H, 4S, ...
[AS, 9H, 8D, 6S, QH, AC, 4C, 9C, QD, KD, 6H, 3D, 3C, 5H, 2C, 6C, ...
[AC, 2C, 3C, 4C, 5C, 6C, 7C, 8C, 9C, 10C, JC, QC, KC, AD, 2D, 3D, ...

Anonymous Classes

Bringing it together: Sort a map by value

Summary

Job Interview Question #2

Given a string, titlecase all of the words in that string.
(Titlecase = intialial capital letter and the rest lowercase.)

A couple different approaches:

  /**
   * Uppercases the first letter of every token in the given str.
   * Tokens must be separated by spaces (only).  Replaces any string of
   * spaces with a single space.
   */
  public static String toTitleCase(String str) {
    String[] tokens = str.split(" +");  //regular expression: 1 or more spaces
    StringBuilder sb = new StringBuilder();
    for (String token : tokens) {
      if (token.length() > 0) {
        sb.append(Character.toUpperCase(token.charAt(0)));
        sb.append(token.substring(1).toLowerCase());
        sb.append(' ');
      }
    }
    return sb.toString();
  }
  /**
   * Uppercases the first letter of every token in the given str.
   * Also replaces any string of whitespace characters with a single space.
   */
  public static String toTitleCase(String str) {
    Scanner scan = new Scanner(str);
    StringBuilder sb = new StringBuilder();
    while (scan.hasNext()) {
      String token = scan.next();
      sb.append(Character.toUpperCase(token.charAt(0)));
      if (token.length() > 1) {
        sb.append(token.substring(1).toLowerCase());
      }
      if (scan.hasNext()) {
        sb.append(' ');
      }
    }
    return sb.toString();
  }

Others (probably better) are possible.

Job Interview Question #3

We're going to play a game.
* First person gets to announce a number between 1 and 10.
* Then, starting with second person, each player take turns adding a value 
   b/w 1 and 10 to the running total.  Announces the new total.
* First person to say "fifty" wins the game.
* Is there a strategy that always lets you win this game? If so, what is it?
* What if we change the target from 50 to a different value?  Is your strategy general?
* Does it matter to your strategy whether you are the first player?

For next time...