1

I have two entities, Person and Age. While the values of Person are unique, Age can be be same for multiple Person.

If I wanted to only lookup Age of a Person, I would have used a HashMap. But I also want to retrieve a list of Person of a particular Age. The solution I can think of is having another HashMap<String, List<Long>> for the reverse lookup. Is there a data structure or a map like interface with O(1) lookup in both the directions that does the job of two HashMap's in one? Please note that I used Person and Age as a trivial example, and that the real examples are not something stored in a database, but fetched from a service, so I have to handle them as I get.

Update:

I think Guavas MultiMap can solve this issue. Because in my case both the key and value are String, so it will work. Just seems a little unclean though.

Dhiresh Jain
  • 369
  • 4
  • 14
  • 2
    Possible duplicate of [Bidirectional Map](https://stackoverflow.com/questions/9783020/bidirectional-map) – Matthew McPeak May 18 '18 at 14:09
  • 1
    This is not a "reverse" it's an additional key (it's not just `String->Person` and `Person->String`, you have an additional `Integer->List`). I believe that warrants an additional map/multimap, although it could reuse the same `Person` objects in value lists. – ernest_k May 18 '18 at 14:09
  • @ernest-kiwele yes I guess it is not exactly reverse. But I want to do two types of queries, `Person`->`Age` and `Age`->`List`. I just wanted to know if there's one interface that gives both functionalities, because otherwise I need to maintain two HashMaps and make sure when I add a new `Person`, I also correctly add it to the `List` for that `Age`. – Dhiresh Jain May 18 '18 at 14:20
  • 1
    @DhireshJain perhaps take a look at this example using Guava: https://stackoverflow.com/a/3678660/6391367. It allows you to create a `ListMultimap` with a `value => key` mapping from a `Map`. – explv May 18 '18 at 14:25

2 Answers2

2

It depends how complex your requirement is - I have had a similar situation in the past but my situation was a bit more complex and I had 4 or 5 fields that I wanted to be able to look up on, so what I ended up doing was using an in-memory database (I used H2 but there are a few). I then indexed all the fields that I wanted to be able to look up by. Because it's in-memory, you get very fast speeds and if you use JPA etc the code is still pretty clean. Clearly this is more complicated that just using a HashMap but will scale better if your requirements get more complex.

Matt
  • 3,237
  • 5
  • 27
  • 52
0

if you use java 1.8+ you can use ".stream()" function, for example:

public static void main(String[] args ) {

    List<Person> personList = new ArrayList<>();
    //...
    List<Person> listOfPersonsWith28 = 
            personList.stream()
            .filter(person -> person.getMyAge().value == 28)
            .collect(Collectors.toList());
}

class Age{
    public int value;
    //...
}

class Person{
    private Age myAge;

    public Age getMyAge() {
        return myAge;
    }
    public void setMyAge(Age myAge) {
        this.myAge = myAge;
    }

}
  • This is nice simple code, but is not O(1) so it would depend on the size of the list as to whether the performance would be acceptable (you could even parallelize the stream to speed it up even more but eventually it will get sluggish) – Matt May 18 '18 at 14:49