I am aware that Google's guava and even Apache commons offer bi-directional maps. However, I would like to know how they are implemented. From the little I found, the most simplest way is to use 2 separate maps to store key/value and value/key data. However, surely there are better ways? Surely Google's implementation is not this straightforward? Where is the magic?
Thanks!
Apparently that's all it is (Louis Wasserman).
If you think about it, a type of bidirectional map could actually be implemented with a single Object->Object map, with the (key,value) pair inserted into the map twice, once for each direction. As long as you didn't require an explicit inverse view, it would work. In the case where the keys and values were of the same type (allowing the same object to be a key and a value), you could only have a single mapping between a given key and value (O1->O2 implying O2->O1), whereas with traditional BiMaps you could effectively have two (O1->O2 with inverse O2->O1 AND O3->O1 with inverse O1->O3). But for many bidirectional map needs, the single-map solution would suffice.
Related
My application requires a multivaluemap to store in redis cache with a key having 2 different objects saying object1 and object2. Map can return all the values or a single value based on type parameter as in get(key, type).
Couldn't find such feature in either reddison or jedis. Is there any other library providing this data structure or I would have to implement my own?
As I know, there is no this kind of data structure in Redis, you have to do a little design by yourself, using extra keys to store extra information.
I need to use some kind of double map in my project. I can imagine this as Map with common key and triple value, but maybe there's better option.
Is there any implementations of this kind of map? Maybe some free library?
Create two small Java POJOs for title and value attributes MyKey and MyValue and you can now have Map<MyKey, MyValue> in this case you can extend the attributes of the Key and Value in future.
You could use a Triplet from http://www.javatuples.org/.
Or, you could create your own class, like shown here: https://stackoverflow.com/a/2671052/5066232.
I need to implement an n:m relation in Java.
The use case is a catalog.
a product can be in multiple categories
a category can hold multiple products
My current solution is to have a mapping class that has two hashmaps.
The key of the first hashmap is the product id and the value is a list of category ids
The key to the second hashmap is the category id and the value is a list of product ids
This is totally redundant an I need a setting class that always takes care that the data is stored/deleted in both hashmaps.
But this is the only way I found to make the following performant in O(1):
what products holds a category?
what categories is a product in?
I want to avoid full array scans or something like that in every way.
But there must be another, more elegant solution where I don't need to index the data twice.
Please en-light me. I have only plain Java, no database or SQLite or something available. I also don't really want to implement a btree structure if possible.
If you associate Categories with Products via a member collection, and vica versa, then you can accomplish the same thing:
public class Product {
private Set<Category> categories = new HashSet<Category>();
//implement hashCode and equals, potentially by id for extra performance
}
public class Category {
private Set<Product> contents = new HashSet<Product>();
//implement hashCode and equals, potentially by id for extra performance
}
The only difficult part is populating such a structure, where some intermediate maps might be needed.
But the approach of using auxiliary hashmaps/trees for indexing is not a bad one. After all, most indices placed on databases for example are auxiliary data structures: they coexist with the table of rows; the rows aren't necessarily organized in the structure of the index itself.
Using an external structure like this empowers you to keep optimizations and data separate from each other; that's not a bad thing. Especially if tomorrow you want to add O(1) look-ups for Products given a Vendor, e.g.
Edit: By the way, it looks like what you want is an implementation of a Multimap optimized to do reverse lookups in O(1) as well. I don't think Guava has something to do that, but you could implement the Multimap interface so at least you don't have to deal with maintaining the HashMaps separately. Actually it's more like a BiMap that is also a Multimap which is contradictory given their definitions. I agree with MStodd that you probably want to roll your own layer of abstraction to encapsulate the two maps.
Your solution is perfectly good. Remember that putting an object into a HashMap doesn't make a copy of the Object, it just stores a reference to it, so the cost in time and memory is quite small.
I would go with your first solution. Have a layer of abstraction around two hashmaps. If you're worried about concurrency, implement appropriate locking for CRUD.
If you're able to use an immutable data structure, Guava's ImmutableMultimap offers an inverse() method, which enables you to get a collection of keys by value.
I need to store data in memory where I map one or more key strings to an object, as follows:
"green", "blue" -> object1
"red", "yellow" -> object2
So, in Java the datastructure might implement:
Map<Set<String>, V>
I need to be able to efficiently receive a list of objects, where the strings match some boolean criteria, such as:
("red" OR "green") AND NOT "blue"
I'm working in Java, so the ideal solution would be an off-the-shelf Java library. I am, however, willing to implement something from scratch if necessary.
Anyone have any ideas? I'd rather avoid the overhead of an in-memory database if possible, I'm hoping for something comparable in speed to a HashMap (or at least the same order of magnitude).
Actually, I liked the problem so I implemented a full solution in the spirit of my earlier answer:
http://pastebin.com/6iazSKG9
A simple solution, not thread safe or anything, but fun and a good starting point, I guess.
Edit: Some elaboration, as requested
See the unit test for usage.
There are two interfaces, DataStructure<K,V> and Query<V>. DataStructure behaves somewhat like a map (and in my implementation it actually works with an internal map), but it also provides reuseable and immutable query objects which can be combined like this:
Query<String> combinedQuery =
structure.and(
structure.or(
structure.search("blue"),
structure.search("red")
),
structure.not(
structure.search("green")
)
);
(A Query that searches for objects that are tagged as (blue OR red) AND NOT green). This query is reuseable, which means that it's results will change whenever the backing map is changed (kind of like an ITunes smart playlist).
The query objects are already thread safe, but the backing map is not, so there is some room for improvement here. Also, the queries could cache their results, but that would probably mean that the interface would have to be extended to provide for a purge method (kind of like the detach method in Wicket's models), which wouldn't be pretty.
As for licensing: if anybody wants this code I'll be happy to put it on SourceForge etc. ...
Sean
Would the criteria be amenable to bitmap indexing: http://en.wikipedia.org/wiki/Bitmap_index ?
I would say that the easiest way is simply to do a recursive filtering and being cleaver, when for instance evaluating X AND Y where X has been evaluated to the empty set.
The mapping however, needs to be from tags (such as "red" or "blue") to sets of objects.
The base case (resolving the atomic tags) of the recursion, would then be a simple lookup in this map. AND would be implemented using intersection, OR using union, and so on.
Check out the Apache Commons - Collections project. They have tons of great stuff that you will be able to use, particularly the CollectionUtils class for performing strong collection-based logic.
For instance, if your values were stored in a HashMap (as suggested by another answer) as follows:
myMap["green"] -> obj1
myMap["blue"] -> obj1
myMap["red"] -> obj2
myMap["yellow"] -> obj2
Then to retrieve results that match: ("red" or "green") and not "blue you might do this:
CollectionUtils.disjunction(CollectionUtils.union(myMap.get("red"), myMap.get("green")), myMap.get("blue"))
You could map string keys to a binary constant, then use bit shifting to produce an appropriate mask.
i truly think some type of database solution is your best bet. SQL easily supports querying data by
(X and Y) and not Z
this would have worked too reusable condition/expression classes
The Google Collections SetMultimap looks like an easy way to get the underlying structure, then combining that with the Maps static filters to get the querying behavior you want.
Construction would go something like
smmInstance.put(from1,to1);
smmInstance.put(from1,to2);
smmInstance.put(from2,to3);
smmInstance.put(from3,to1);
smmInstance.put(from1,to3);
//...
queries would then look like
valueFilter = //...build predicate
Set<FromType> result = Maps.filterValues(smmInstance.asMap(),valueFilter).keySet()
You can do any amount of fancy building the predicate, but Predicates has a few methods that would probably be enough to do contains/doesn't contain style queries.
I wasn't able to find a satisfactory solution, so I decided to cook up my own and release it as an open source (LGPL) project, find it here.
I need a map that has two keys, e.g.
Map2<String /*ssn*/, String /*empId*/, Employee> _employees;
So that I can
_employees.put(e.ssn(), e.empId(), e)
And later
_employees.get1(someSsn);
_employees.get2(someImpId);
Or even
_employees.remove1(someImpId);
I am not sure why I want to stop at two, why not more, probably because that's the case I am I need right now :-) But the type needs to handle fixed number of keys to be type-safe -- type parameters cannot be vararg :-)
Appreciate any pointers, or advice on why this is a bad idea.
I imagine the main key would be empId, so I would build a Map with that as the key, i.e. empId ---> Employee. All other unique attributes (e.g. ssn) would be treated as secondary and will use separate Maps as a lookup table for empId (e.g. ssn ---> empId).
This implementation makes it easy to add/remove employees, since you only need to change one Map, i.e. empId ---> Employee; the other Maps can be rebuilt only when needed.
My first thought was: the easiest way to do this, I think, would be two maps.
Map< String, Map< String,Employee> > _employees;
But from what it looks like, you just want to be able to look up an employee by either SSN or ID. What's to stop you then from making two maps, or at worst a class that contains two maps?
As a clarification, are you looking for a compound key being employees are uniquely identified by the combination of their SSN and ID, but not either one by itself, or are you looking for two different ways of referencing an employee?
The Spiffy Framework appears to provide exactly what you`re looking for. From the Javadocs:
A two-dimensional hashmap, is a
HashMap that enables you to refer to
values via two keys rather than one
The relevant class is TwoDHashMap. It also provides a ThreeDHashMap.