Advertisement
Guest User

In memory data structure

a guest
May 20th, 2010
455
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 7.62 KB | None | 0 0
  1. /*******************************************************************************
  2. * To test this you either have to split this file into many different classes  *
  3. * or do a global search / replace from 'public class' to 'public static class' *
  4. * and place the entire code inside a new empty class (for quick testing only)  *
  5. * The unit test below has to be in it's own .java file, or it won't run        *
  6. *                                                                              *
  7. * Questions, ideas, copyright: Sean Floyd <sean@mostlymagic.com>               *
  8. *                                                                              *
  9. * Inspired by this question:                                                   *
  10. * http://stackoverflow.com/questions                                           *
  11. *       /2874139/in-memory-data-structure-that-supports-boolean-querying       *
  12. *******************************************************************************/
  13.  
  14.  
  15.  
  16. /***** Interfaces *************************************************************/
  17.  
  18. public interface Query<T> {
  19.     Collection<T> get();
  20. }
  21.  
  22. public interface DataStructure<K, V> {
  23.     Query<V> and(Query<V> first, Query<V> second);
  24.  
  25.     Collection<K> keys();
  26.  
  27.     Query<V> not(Query<V> inner);
  28.  
  29.     Query<V> or(Query<V> first, Query<V> second);
  30.  
  31.     void put(V value, K... keys);
  32.  
  33.     void removeKey(K key);
  34.  
  35.     void removeValue(V value);
  36.  
  37.     Query<V> search(K key);
  38.  
  39.     Collection<V> values();
  40.  
  41.     Collection<V> values(K key);
  42. }
  43.  
  44. /***** Implementation *********************************************************/
  45.  
  46. public class DataStructureImpl<K, V> implements DataStructure<K, V> {
  47.  
  48.     private final Map<K, Collection<V>> map = new HashMap<K, Collection<V>>();
  49.  
  50.     @Override
  51.     public Query<V> and(final Query<V> first, final Query<V> second) {
  52.         return new AndQuery<V>(first, second);
  53.     }
  54.  
  55.     @Override
  56.     public Collection<K> keys() {
  57.         return new HashSet<K>(this.map.keySet());
  58.     }
  59.  
  60.     @Override
  61.     public Query<V> not(final Query<V> inner) {
  62.         return new NotQuery<K, V>(inner, this);
  63.     }
  64.  
  65.     @Override
  66.     public Query<V> or(final Query<V> first, final Query<V> second) {
  67.         return new OrQuery<V>(first, second);
  68.     }
  69.  
  70.     @Override
  71.     public void put(final V value, final K... keys) {
  72.         for (final K key : keys) {
  73.             if (!this.map.containsKey(key)) {
  74.                 this.map.put(key, new HashSet<V>());
  75.             }
  76.             this.map.get(key).add(value);
  77.         }
  78.  
  79.     }
  80.  
  81.     @Override
  82.     public void removeKey(final K key) {
  83.         this.map.remove(key);
  84.     }
  85.  
  86.     @Override
  87.     public void removeValue(final V value) {
  88.         final Collection<K> keysToRemove = new HashSet<K>();
  89.         for (final Entry<K, Collection<V>> entry : this.map.entrySet()) {
  90.             final Collection<V> rowValue = entry.getValue();
  91.             if (rowValue.remove(rowValue) && rowValue.isEmpty()) {
  92.                 keysToRemove.add(entry.getKey());
  93.             }
  94.         }
  95.         for (final K key : keysToRemove) {
  96.             this.map.remove(key);
  97.         }
  98.     }
  99.  
  100.     @Override
  101.     public Query<V> search(final K key) {
  102.         return new SearchQuery<K, V>(key, this);
  103.     }
  104.  
  105.     @Override
  106.     public Collection<V> values() {
  107.         final Set<V> set = new HashSet<V>();
  108.         for (final Collection<V> row : this.map.values()) {
  109.             set.addAll(row);
  110.         }
  111.         return set;
  112.     }
  113.  
  114.     @Override
  115.     public Collection<V> values(final K key) {
  116.         return new HashSet<V>(this.map.containsKey(key) ? this.map.get(key)
  117.                 : Collections.<V> emptySet());
  118.     }
  119.  
  120. }
  121.  
  122. public class AndQuery<V> implements Query<V> {
  123.  
  124.     private final Query<V> first;
  125.     private final Query<V> second;
  126.  
  127.     public AndQuery(final Query<V> first, final Query<V> second) {
  128.         this.first = first;
  129.         this.second = second;
  130.     }
  131.  
  132.     @Override
  133.     public Collection<V> get() {
  134.         final Collection<V> result = new ArrayList<V>(this.first.get());
  135.         result.retainAll(this.second.get());
  136.         return result;
  137.     }
  138.  
  139. }
  140.  
  141.  
  142.  
  143.  
  144. public class NotQuery<K, V> implements Query<V> {
  145.  
  146.     private final DataStructure<K, V> dataStructure;
  147.     private final Query<V> inner;
  148.  
  149.     public NotQuery(final Query<V> inner,
  150.             final DataStructure<K, V> dataStructure) {
  151.         this.inner = inner;
  152.         this.dataStructure = dataStructure;
  153.     }
  154.  
  155.     @Override
  156.     public Collection<V> get() {
  157.         final Collection<V> values = this.dataStructure.values();
  158.         values.removeAll(this.inner.get());
  159.         return values;
  160.     }
  161.  
  162. }
  163.  
  164. public class OrQuery<V> implements Query<V> {
  165.  
  166.     private final Query<V> first;
  167.     private final Query<V> second;
  168.  
  169.     public OrQuery(final Query<V> first, final Query<V> second) {
  170.         this.first = first;
  171.         this.second = second;
  172.     }
  173.  
  174.     @Override
  175.     public Collection<V> get() {
  176.         final Collection<V> result = new HashSet<V>(this.first.get());
  177.         result.addAll(this.second.get());
  178.         return result;
  179.     }
  180.  
  181. }
  182.  
  183.  
  184. public class SearchQuery<K, V> implements Query<V> {
  185.  
  186.     private final K key;
  187.     private final DataStructure<K, V> dataStructure;
  188.  
  189.     public SearchQuery(final K key, final DataStructure<K, V> dataStructure) {
  190.         this.key = key;
  191.         this.dataStructure = dataStructure;
  192.     }
  193.  
  194.     @Override
  195.     public Collection<V> get() {
  196.         return this.dataStructure.values(this.key);
  197.     }
  198.  
  199. }
  200.  
  201. /***** JUnit Test *************************************************************/
  202.  
  203. public class DataStructureImplTest {
  204.     enum Color {
  205.  
  206.         RED, BLUE, GREEN, BLACK, PINK, MAUVE, TURQUOISE, YELLOW, MAGENTA, GRAY, WHITE, BROWN;
  207.  
  208.     }
  209.  
  210.     enum Toon {
  211.  
  212.         TOM, JERRY, BUGS, DAFFY, MICKEY, DONALD, DAISY, GOOFY, WILEY;
  213.  
  214.     }
  215.  
  216.     private DataStructure<Color, Toon> data;
  217.  
  218.     @Before
  219.     public void setup() {
  220.         this.data = new DataStructureImpl<Color, Toon>();
  221.  
  222.         this.data.put(Toon.DONALD, Color.YELLOW, Color.BLUE, Color.WHITE);
  223.         this.data.put(Toon.MICKEY, Color.BLACK, Color.WHITE, Color.RED);
  224.         this.data.put(Toon.WILEY, Color.GRAY);
  225.         this.data.put(Toon.TOM, Color.GRAY, Color.WHITE);
  226.         this.data.put(Toon.JERRY, Color.BROWN);
  227.         this.data.put(Toon.GOOFY, Color.BLACK, Color.WHITE, Color.RED);
  228.         this.data.put(Toon.BUGS, Color.WHITE, Color.GRAY);
  229.         this.data.put(Toon.DAISY, Color.PINK);
  230.         this.data.put(Toon.DAFFY, Color.BLACK, Color.YELLOW);
  231.     }
  232.  
  233.     @Test
  234.     public void testCombinedQueries() {
  235.         final Query<Toon> whiteQuery = this.data.search(Color.WHITE);
  236.         final Query<Toon> blackQuery = this.data.search(Color.BLACK);
  237.         final Query<Toon> redQuery = this.data.search(Color.RED);
  238.  
  239.         final Collection<Toon> blackOrWhite = this.data.or(blackQuery,
  240.                 whiteQuery).get();
  241.         assertTrue(blackOrWhite.containsAll(EnumSet.of(Toon.DONALD,
  242.                 Toon.MICKEY, Toon.DAFFY)));
  243.         assertFalse(blackOrWhite.contains(Toon.WILEY));
  244.  
  245.         final Collection<Toon> blackAndWhite = this.data.and(blackQuery,
  246.                 whiteQuery).get();
  247.         assertTrue(blackAndWhite.containsAll(EnumSet
  248.                 .of(Toon.MICKEY, Toon.GOOFY)));
  249.         assertFalse(blackAndWhite.contains(Toon.DONALD));
  250.  
  251.         final Collection<Toon> notWhite = this.data.not(whiteQuery).get();
  252.         assertTrue(notWhite.containsAll(EnumSet.of(Toon.DAFFY, Toon.WILEY,
  253.                 Toon.JERRY)));
  254.         assertFalse(notWhite.contains(Toon.TOM));
  255.  
  256.         final Collection<Toon> blackAndEitherWhiteOrNotRed = this.data.and(
  257.                 blackQuery, this.data.or(whiteQuery, this.data.not(redQuery)))
  258.                 .get();
  259.         assertTrue(blackAndEitherWhiteOrNotRed.containsAll(EnumSet.of(
  260.                 Toon.MICKEY, Toon.GOOFY, Toon.DAFFY)));
  261.  
  262.     }
  263.  
  264.     @Test
  265.     public void testSimpleQuery() {
  266.  
  267.         final Query<Toon> whiteQuery = this.data.search(Color.WHITE);
  268.         assertTrue(whiteQuery.get().containsAll(
  269.                 EnumSet.of(Toon.DONALD, Toon.MICKEY)));
  270.         assertFalse(whiteQuery.get().contains(Toon.WILEY));
  271.  
  272.     }
  273. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement