Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the best approach to remove from a map when value is greater than x

I am trying to create a Map<String, Date> that can hold values until the date value > 1 day old.

Is the best approach to do this to use a ConcurrentHashMap and then create a thread which iterates the map once every minute or so and then remove the values older than 1 day, or, is there a better approach to doing this?

For clarification the date message received will not be the current time, it can be a time previous

Thanks

like image 290
Biscuit128 Avatar asked Aug 01 '14 18:08

Biscuit128


2 Answers

EDIT: OK, so I have edited all of the below to use an Optional<Date> because Guava's caches don't like the Callable or CacheLoader to return null and you want to use this as a Map where the value associated with a key may be absent.

Use Guava's Cache

Cache<Key, Graph> graphs = CacheBuilder.newBuilder()
   .expireAfterWrite(1, TimeUnit.DAYS)
   .build();

Loading Cache would be...

   LoadingCache<String, Optional<Date>> graphs = CacheBuilder.newBuilder()
   .expireAfterWrite(1, TimeUnit.DAYS)
   .build(
       new CacheLoader<String, Optional<Date>>() {
         public Optional<Date>load(Stringkey) throws AnyException {
           return Optional.absent();
         }
       });

Ok, so I think what you want if the Date may have been in the past is to wrap the above Cache in a ForwardingCache.SimpleForwardingCache. You then overload the get method to return null if the Date value is older than a day.

Cache<String, Optional<Date>> cache = new SimpleForwardingCache<>(grapsh){

      public Optional<Date>get(String key, Callable<Optional<Date>> valueLoader){
           Optional<Date> result = delegate().get(key, valueLoader);
           if (!result.isPresent() || olderThanADay(result.get()))
                return Optional.absent();
           else
                return result;
      }

      // since you don't really need a valueLoader you might want to add this.
      // this is in place of the LoadingCache, if use LoadingCache use 
      // ForwardingLoadingCache
      public Date get(String key){
          return get(key, 
               new Callable<Optional<Date>>(){
                 public Date call(){return Optional.absent();}
               }
      }
 }
like image 172
John B Avatar answered Oct 17 '22 22:10

John B


I would probably create a custom class that contains a HashMap, as well as a priority queue of the objects that are also stored in the HashMap. The priority queue is ordered by the system time when the object is too old.

After that, you can have an internal private thread of some kind that sleeps until the next time the first object in the priority queue needs to be removed from the queue and also removed from the HashMap. No need to loop through the HashMap, or check values at a certain rate.

If you don't need to implement it yourself go with a third party library solution like the other answer.

like image 1
NESPowerGlove Avatar answered Oct 17 '22 21:10

NESPowerGlove