Filter a MultiMap<Predicate, value>

1.1k views Asked by At

Block are some long-lived instances representing types, e.g. A Minecraft BlockType grass, green_wool etc.

I'm trying to find a DataStructure that can efficiently store and test for a given BlockPattern (think like, an obsidian portal, Wither etc if you are familiar with Minecraft) but if you are not familiar, being able to create a class that can test for a given structure being built out of blocks at given Vector3i's relative to the block being placed.

The Vector3i represents an integer vector of where in a 'block pattern' that a given predicate can match to.

e.g. you could have a predicate that tests for an arbitrary block property 'hotness' that tests true for fire and lava.

So rather then scan the whole pattern each time to make sure that the block positions in the world, match the predicates, I was thinking about reversing the problem.

Cache the potential positions that a Block can be in a pattern in a multimap, and get all the potential positions, in order to limit the amount of checks that happen afterwards.

So I have a Multimap<Predicate<Block>,Vector3i> patternLookup cache.

Which is representing the potential positions that a block is allowed to be found in the BlockPattern.

So the player places a Block, I need to filter the Multimap, collecting all possible locations the block is 'allowed' (predicate true) to be in.

However, as an optimization step, I thought it may be faster to only test the predicates that have a potential match (in terms of identity). (3 years on I'm not sure if this assumption is true)

How can I filter the contents of the multimap to get a collection of values, using guava's functional features? (or am I better just iterating over the EntrySet?)

e.g.

1

There are 1 answers

3
dimo414 On

You could use Multimaps.filterEntries(), something like:

public static <V> Multimap<Predicate<V>, V> filterByPredicateKey(
    Multimap<Predicate<V>, V> multimap) {
  return Multimaps.filterEntries(multimap, e -> e.getKey().apply(e.getValue()));
}

That doesn't quite match the multimap type signature you mention in your question, but I assume block and Vector3i are related in some way, otherwise you couldn't apply the predicate to the values anyways.

This returns a view of the backing multimap, which is free (O(1)) to construct but applies the filtering at access time, so .get() on the returned multimap is O(n). Depending on the expected use cases you may prefer to copy this multimap into a separate immutable multimap so the filtering only happens once.