9

I'm using google guava 12 and have a map:

Map<OccupancyType, BigDecimal> roomPrice;

I have a Set:

Set<OccupancyType> policy;

How can I filter entries in the roomPrice map based on policy and return the filtered map ?

filteredMap needs to have all the values from policy. In case, roomPrice map doesnt have an entry from policy, I'd like to input default value instead.

brainydexter
  • 19,826
  • 28
  • 77
  • 115
  • Does this answer your question? [what is the best way to get a sub HashMap based on a list of Keys?](https://stackoverflow.com/questions/28856781/what-is-the-best-way-to-get-a-sub-hashmap-based-on-a-list-of-keys) – tkruse Mar 29 '21 at 11:11

3 Answers3

29

Since you have a Set of keys you should use Maps.filterkeys(), also Guava provides a pretty good set of predicates that you can use out of the box. In your case something like Predicates.in() should work.

So basically you end up with:

Map<OccupancyType, BigDecimal> filteredMap
    = Maps.filterKeys(roomPrice, Predicates.in(policy));

Hope it helps.

Grzegorz Rożniecki
  • 27,415
  • 11
  • 90
  • 112
Francisco Paulo
  • 6,284
  • 26
  • 25
  • Thanks! I'm still very new to Predicates and not sure how it will generate a predicate that would work upon my map. ALso, is there any way to ensure, filteredMap should have all the values from policy. In case, roomPrice map doesnt have an entry from policy, I'd like to input default value instead. – brainydexter Jun 27 '12 at 08:25
  • If you have a map with "default" entries you can do something like: filteredMap.putAll(Maps.difference(filteredMap, defaultMap).entriesOnlyOnRight()); – Francisco Paulo Jun 27 '12 at 08:46
  • 1
    Also, you can take a look at this article: http://scaramoche.blogspot.de/2010/08/googles-guava-library-tutorial-part-4.html It has some nice examples of Predicate usage. – Francisco Paulo Jun 27 '12 at 08:49
  • 1
    Maps.filterKeys() is often a bad solution because it produces a liveView of the original Map with complexity O(n) for methods like contains() or size(). Better use answer from https://stackoverflow.com/questions/28856781 – tkruse Mar 29 '21 at 11:05
2
  • Override and implement equals and hashcode in OccupancyType.
  • Loop through roomPrice's keyset and collect the elements contained in the filter.

Something like this:

Map<OccupancyType, BigDecimal> filteredPrices = new HashMap<OccupancyType, BigDecimal>();
for(OccupancyType key : roomPrice.keySet()) {
    if(policy.contains(key) {
        filteredPrices.put(key, roomPrice.get(key));
    }
}

Update

Ok after reading up a bit on Google Guava, you should be able to do something like:

Predicate<OccupancyType> priceFilter = new Predicate<OccupancyType>() {
    public boolean apply(OccupancyType i) {
        return policy.contains(i);
    }
};

and then

return Maps.filterValues(roomPrice, priceFlter);

should do the trick.

Jeshurun
  • 22,940
  • 6
  • 79
  • 92
  • Thanks! I know that'd work, but am also learning to use guava. I was hoping to use something of the sorts of Maps.filterEntries(...)[link](http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/collect/Maps.html#filterEntries(java.util.Map, com.google.common.base.Predicate))[/link] from google-guava. Would you happen to have any ideas how I could do the above with that ? – brainydexter Jun 27 '12 at 07:51
  • Ok I have updated my answer after reading up on that a bit let me know if it works! – Jeshurun Jun 27 '12 at 08:02
  • Don't you think it should be `Maps.filterEntries(roomPrice, priceFilter);` – brainydexter Jun 27 '12 at 08:04
0

No need to use Guava, also Maps.filterKeys() can produce a result with very bad performance for large Maps.

// (new map can be initialized to better value to avoid resizing)
Map<OccupancyType, BigDecimal> filteredMap = new HashMap<>(roomPrice.size());
for (OccupancyType key: policy) {
    // contains() and get() can usually be combined
    if (roomPrice.contains(key)) {
       filteredMap.put(key, roomPrice.get(key));
    }
}
tkruse
  • 10,222
  • 7
  • 53
  • 80