Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Apr 28th, 2012  |  syntax: None  |  size: 10.04 KB  |  hits: 12  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. Memory efficient multivaluemap
  2. int getPackedInt(byte[] array, int index) {
  3.   int i = index*3;
  4.   return ((array[i] & 0xFF)<<16) + ((array[i+1] & 0xFF) <<8) + (array[i+2] & 0xFF);
  5. }
  6. int storePackedInt(byte[] array, int index, int value) {
  7.   assert value >= 0 && value <= 0xFFFFFF;
  8.   int i = index*3;
  9.   array[i]   = (byte)((value>>16) & 0xFF);
  10.   array[i+1] = (byte)((value>>8)  & 0xFF);
  11.   array[i+2] = (byte)(value & 0xFF);
  12. }
  13.        
  14. ListMultimap<String, Integer> multimap = Multimaps.newListMultimap(
  15.   new HashMap<String, Collection<Integer>>(),
  16.   new Supplier<List<Integer>>() {
  17.     public List<Integer> get() {
  18.       return new TIntListDecorator();
  19.     }
  20.   });
  21.        
  22. /**
  23.  * Implementation of a Trie structure.
  24.  *
  25.  * A Trie is a compact form of tree that takes advantage of common prefixes
  26.  * to the keys.
  27.  *
  28.  * A normal HashSet will take the key and compute a hash from it, this hash will
  29.  * be used to locate the value through various methods but usually some kind
  30.  * of bucket system is used. The memory footprint resulting becomes something
  31.  * like O(n).
  32.  *
  33.  * A Trie structure essentuially combines all common prefixes into a single key.
  34.  * For example, holding the strings A, AB, ABC and ABCD will only take enough
  35.  * space to record the presence of ABCD. The presence of the others will be
  36.  * recorded as flags within the record of ABCD structure at zero cost.
  37.  *
  38.  * This structure is useful for holding similar strings such as product IDs or
  39.  * credit card numbers.
  40.  *  
  41.  */
  42. public class TrieMap<V> extends AbstractMap<String, V> implements Map<String, V> {
  43.  
  44.  
  45.   /**
  46.    * Map each character to a sub-trie.
  47.    *
  48.    * Could replace this with a 256 entry array of Tries but this will handle
  49.    * multibyte character sets and I can discard empty maps.
  50.    *
  51.    * Maintained at null until needed (for better memory footprint).
  52.    *
  53.    */
  54.   protected Map<Character, TrieMap<V>> children = null;
  55.  
  56.   /**
  57.    * Here we store the map contents.
  58.    */
  59.   protected V leaf = null;
  60.  
  61.   /**
  62.    * Set the leaf value to a new setting and return the old one.
  63.    *
  64.    * @param newValue
  65.    * @return old value of leaf.
  66.    */
  67.   protected V setLeaf(V newValue) {
  68.     V old = leaf;
  69.     leaf = newValue;
  70.     return old;
  71.   }
  72.  
  73.   /**
  74.    * I've always wanted to name a method something like this.
  75.    */
  76.   protected void makeChildren () {
  77.     if ( children == null ) {
  78.       // Use a TreeMap to ensure sorted iteration.
  79.       children = new TreeMap<Character, TrieMap<V>>();
  80.     }
  81.   }
  82.  
  83.   /**
  84.    * Finds the TrieMap that "should" contain the key.
  85.    *
  86.    * @param key
  87.    *
  88.    * The key to find.
  89.    *
  90.    * @param grow
  91.    *
  92.    * Set to true to grow the Trie to fit the key.
  93.    *
  94.    * @return
  95.    *
  96.    * The sub Trie that "should" contain the key or null if key was not found and
  97.    * grow was false.
  98.    */
  99.   protected TrieMap<V> find(String key, boolean grow) {
  100.     if (key.length() == 0) {
  101.       // Found it!
  102.       return this;
  103.     } else {
  104.       // Not at end of string.
  105.       if (grow) {
  106.         // Grow the tree.
  107.         makeChildren();
  108.       }
  109.       if (children != null) {
  110.         // Ask the kids.
  111.         char ch = key.charAt(0);
  112.         TrieMap<V> child = children.get(ch);
  113.         if (child == null && grow) {
  114.           // Make the child.
  115.           child = new TrieMap<V>();
  116.           // Store the child.
  117.           children.put(ch, child);
  118.         }
  119.         if (child != null) {
  120.           // Find it in the child.
  121.           return child.find(tail(key), grow);
  122.         }
  123.       }
  124.     }
  125.     return null;
  126.  
  127.   }
  128.  
  129.   /**
  130.    * Remove the head (first character) from the string.
  131.    *
  132.    * @param s
  133.    *
  134.    * The string.
  135.    *
  136.    * @return
  137.    *
  138.    * The same string without the first (head) character.
  139.    *
  140.    */
  141.   // Suppress warnings over taking a subsequence
  142.   private String tail(String s) {
  143.     return s.substring(1, s.length());
  144.   }
  145.  
  146.   /**
  147.    *
  148.    * Add a new value to the map.
  149.    *
  150.    * Time footprint = O(s.length).
  151.    *
  152.    * @param s
  153.    *
  154.    * The key defining the place to add.
  155.    *
  156.    * @param value
  157.    *
  158.    * The value to add there.
  159.    *
  160.    * @return
  161.    *
  162.    * The value that was there, or null if it wasn't.
  163.    *
  164.    */
  165.   @Override
  166.   public V put(String key, V value) {
  167.     V old = null;
  168.  
  169.     // If empty string.
  170.     if (key.length() == 0) {
  171.       old = setLeaf(value);
  172.     } else {
  173.       // Find it.
  174.       old = find(key, true).put("", value);
  175.     }
  176.  
  177.     return old;
  178.   }
  179.  
  180.   /**
  181.    * Gets the value at the specified key position.
  182.    *
  183.    * @param o
  184.    *
  185.    * The key to the location.
  186.    *
  187.    * @return
  188.    *
  189.    * The value at that location, or null if there is no value at that location.
  190.    */
  191.   @Override
  192.   public V get(Object o) {
  193.     V got = null;
  194.     if (o != null) {
  195.       String key = (String) o;
  196.       TrieMap<V> it = find(key, false);
  197.       if (it != null) {
  198.         got = it.leaf;
  199.       }
  200.     } else {
  201.       throw new NullPointerException("Nulls not allowed.");
  202.     }
  203.     return got;
  204.   }
  205.  
  206.   /**
  207.    * Remove the value at the specified location.
  208.    *
  209.    * @param o
  210.    *
  211.    * The key to the location.
  212.    *
  213.    * @return
  214.    *
  215.    * The value that was removed, or null if there was no value at that location.
  216.    */
  217.   @Override
  218.   public V remove(Object o) {
  219.     V old = null;
  220.     if (o != null) {
  221.       String key = (String) o;
  222.       if (key.length() == 0) {
  223.         // Its me!
  224.         old = leaf;
  225.         leaf = null;
  226.       } else {
  227.         TrieMap<V> it = find(key, false);
  228.         if (it != null) {
  229.           old = it.remove("");
  230.         }
  231.       }
  232.     } else {
  233.       throw new NullPointerException("Nulls not allowed.");
  234.     }
  235.     return old;
  236.   }
  237.  
  238.   /**
  239.    * Count the number of values in the structure.
  240.    *
  241.    * @return
  242.    *
  243.    * The number of values in the structure.
  244.    */
  245.   @Override
  246.   public int size() {
  247.     // If I am a leaf then size increases by 1.
  248.     int size = leaf != null ? 1 : 0;
  249.     if (children != null) {
  250.       // Add sizes of all my children.
  251.       for (Character c : children.keySet()) {
  252.         size += children.get(c).size();
  253.       }
  254.     }
  255.     return size;
  256.   }
  257.  
  258.   /**
  259.    * Is the tree empty?
  260.    *
  261.    * @return
  262.    *
  263.    * true if the tree is empty.
  264.    * false if there is still at least one value in the tree.
  265.    */
  266.   @Override
  267.   public boolean isEmpty() {
  268.     // I am empty if I am not a leaf and I have no children
  269.     // (slightly quicker than the AbstaractCollection implementation).
  270.     return leaf == null && (children == null || children.isEmpty());
  271.   }
  272.  
  273.   /**
  274.    * Returns all keys as a Set.
  275.    *
  276.    * @return
  277.    *
  278.    * A HashSet of all keys.
  279.    *
  280.    * Note: Although it returns Set<S> it is actually a Set<String> that has been
  281.    * home-grown because the original keys are not stored in the structure
  282.    * anywhere.
  283.    */
  284.   @Override
  285.   public Set<String> keySet() {
  286.     // Roll them a temporary list and give them a Set from it.
  287.     return new HashSet<String>(keyList());
  288.   }
  289.  
  290.   /**
  291.    * List all my keys.
  292.    *
  293.    * @return
  294.    *
  295.    * An ArrayList of all keys in the tree.
  296.    *
  297.    * Note: Although it returns List<S> it is actually a List<String> that has been
  298.    * home-grown because the original keys are not stored in the structure
  299.    * anywhere.
  300.    *
  301.    */
  302.   protected List<String> keyList() {
  303.     List<String> contents = new ArrayList<String>();
  304.  
  305.     if (leaf != null) {
  306.       // If I am a leaf, a null string is in the set.
  307.       contents.add((String) "");
  308.     }
  309.  
  310.     // Add all sub-tries.
  311.     if (children != null) {
  312.       for (Character c : children.keySet()) {
  313.         TrieMap<V> child = children.get(c);
  314.         List<String> childContents = child.keyList();
  315.         for (String subString : childContents) {
  316.           // All possible substrings can be prepended with this character.
  317.           contents.add((String) (c + subString.toString()));
  318.         }
  319.       }
  320.     }
  321.  
  322.     return contents;
  323.   }
  324.  
  325.   /**
  326.    * Does the map contain the specified key.
  327.    *
  328.    * @param key
  329.    *
  330.    * The key to look for.
  331.    *
  332.    * @return
  333.    *
  334.    * true if the key is in the Map.
  335.    * false if not.
  336.    */
  337.   public boolean containsKey(String key) {
  338.     TrieMap<V> it = find(key, false);
  339.     if (it != null) {
  340.       return it.leaf != null;
  341.     }
  342.     return false;
  343.   }
  344.  
  345.   /**
  346.    * Represent me as a list.
  347.    *
  348.    * @return
  349.    *
  350.    * A String representation of the tree.
  351.    */
  352.   @Override
  353.   public String toString() {
  354.     List<String> list = keyList();
  355.     //Collections.sort((List<String>)list);
  356.     StringBuilder sb = new StringBuilder();
  357.     Separator comma = new Separator(",");
  358.     sb.append("{");
  359.     for (String s : list) {
  360.       sb.append(comma.sep()).append(s).append("=").append(get(s));
  361.     }
  362.     sb.append("}");
  363.     return sb.toString();
  364.   }
  365.  
  366.   /**
  367.    * Clear down completely.
  368.    */
  369.   @Override
  370.   public void clear() {
  371.     children = null;
  372.     leaf = null;
  373.   }
  374.  
  375.   /**
  376.    * Return a list of key/value pairs.
  377.    *
  378.    * @return
  379.    *
  380.    * The entry set.
  381.    */
  382.   public Set<Map.Entry<String, V>> entrySet() {
  383.     Set<Map.Entry<String, V>> entries = new HashSet<Map.Entry<String, V>>();
  384.     List<String> keys = keyList();
  385.     for (String key : keys) {
  386.       entries.add(new Entry<String,V>(key, get(key)));
  387.     }
  388.     return entries;
  389.   }
  390.  
  391.   /**
  392.    * An entry.
  393.    *
  394.    * @param <S>
  395.    *
  396.    * The type of the key.
  397.    *
  398.    * @param <V>
  399.    *
  400.    * The type of the value.
  401.    */
  402.   private static class Entry<S, V> implements Map.Entry<S, V> {
  403.  
  404.     protected S key;
  405.     protected V value;
  406.  
  407.     public Entry(S key, V value) {
  408.       this.key = key;
  409.       this.value = value;
  410.     }
  411.  
  412.     public S getKey() {
  413.       return key;
  414.     }
  415.  
  416.     public V getValue() {
  417.       return value;
  418.     }
  419.  
  420.     public V setValue(V newValue) {
  421.       V oldValue = value;
  422.       value = newValue;
  423.       return oldValue;
  424.     }
  425.  
  426.     @Override
  427.     public boolean equals(Object o) {
  428.       if (!(o instanceof TrieMap.Entry)) {
  429.         return false;
  430.       }
  431.       Entry e = (Entry) o;
  432.       return (key == null ? e.getKey() == null : key.equals(e.getKey()))
  433.               && (value == null ? e.getValue() == null : value.equals(e.getValue()));
  434.     }
  435.  
  436.     @Override
  437.     public int hashCode() {
  438.       int keyHash = (key == null ? 0 : key.hashCode());
  439.       int valueHash = (value == null ? 0 : value.hashCode());
  440.       return keyHash ^ valueHash;
  441.     }
  442.  
  443.     @Override
  444.     public String toString() {
  445.       return key + "=" + value;
  446.     }
  447.   }
  448. }