Guava: Set + Function = Map?

前端 未结 6 1126
眼角桃花
眼角桃花 2021-02-05 01:40

Is there an idiomatic way to take a Set and a Function, and get a Map live view? (i.e. the Map

6条回答
  •  一整个雨季
    2021-02-05 02:23

    I don't know if this is what you mean by live view.Any way here is my try.

    public class GuavaTst {
    public static void main(String[] args) {
        final Function functionToLower = new Function() {
            public String apply (String input) {
                return input.toLowerCase();
            }
        };
    
          final Set set=new HashSet();
          set.add("Hello");
          set.add("BYE");
          set.add("gOOd");
          Map testMap = newLiveMap(set,functionToLower);
          System.out.println("Map :- "+testMap);
          System.out.println("Set :- "+set);
          set.add("WoRld");
          System.out.println("Map :- "+testMap);
          System.out.println("Set :- "+set);
          testMap.put("OMG","");
          System.out.println("Map :- "+testMap);
          System.out.println("Set :- "+set);
    
     }
    
    
     static  Map newLiveMap(final Set backEnd,final Function fun)
     {
        return new HashMap(){
    
    
                @Override
                public void clear() {
    
                    backEnd.clear();
                }
                @Override
                public boolean containsKey(Object key) {
    
                    return backEnd.contains(key);
                }
                @Override
                public boolean isEmpty() {
    
                    return backEnd.isEmpty();
                }
                @Override
                public V put(K key, V value) {
    
                    backEnd.add(key);
                    return null; 
                }
                @Override
                public boolean containsValue(Object value) {
    
                    for(K s:backEnd)
                        if(fun.apply(s).equals(value))
                            return true;
                    return false;
                }
                @Override
                public V remove(Object key) {
    
                    backEnd.remove(key);
                    return null;
                }
                @Override
                public int size() {
    
                    return backEnd.size();
                }
    
                @Override
                public V get(Object key) {
    
                    return fun.apply((K)key);
                }
                @Override
                public String toString() {
    
                    StringBuilder b=new StringBuilder();
                    Iterator itr=backEnd.iterator();
    
                    b.append("{");
                    if(itr.hasNext())
                    {
                     K key=itr.next();  
                     b.append(key);
                     b.append(":");
                     b.append(this.get(key));
    
                     while(itr.hasNext())
                     {
                      key=itr.next();
                      b.append(", ");
                      b.append(key);
                      b.append(":");
                      b.append(this.get(key));   
                     }
                    }
    
                    b.append("}");
    
                    return b.toString();
                }
            };              
     } 
    }
    

    The implementation is not complete and the overridden functions are not tested but I hope it convey's the idea.

    UPDATE:

    I made some small change's to seanizer's answer so that the changes made in map will reflect in the set also.

    public class SetBackedMap extends AbstractMap implements SetFunctionMap{
    
        public class MapEntry implements Entry{
            private final K key;
            public MapEntry(final K key){
                this.key = key;
            }
            @Override
            public K getKey(){
                return this.key;
            }
            @Override
            public V getValue(){
                V value = SetBackedMap.this.cache.get(this.key);
                if(value == null){
                    value = SetBackedMap.this.funk.apply(this.key);
                    SetBackedMap.this.cache.put(this.key, value);
                }
                return value;
            }
            @Override
            public V setValue(final V value){
                throw new UnsupportedOperationException();
            }
        }
    
    
    
        public class EntrySet extends AbstractSet>{
    
            public class EntryIterator implements Iterator>{
                private final Iterator inner;
                public EntryIterator(){
                    this.inner = EntrySet.this.keys.iterator();
                }
    
                @Override
                public boolean hasNext(){
                    return this.inner.hasNext();
                }
                @Override
                public Map.Entry next(){
                    final K key = this.inner.next();
                    return new MapEntry(key);
                }
                @Override
                public void remove(){
                    throw new UnsupportedOperationException();
                }
    
    
            }
    
            private final Set keys;
    
            public EntrySet(final Set keys){
                this.keys = keys;
            }
            @Override
            public boolean add(Entry e) {
                return keys.add(e.getKey());
            }
            @Override
            public Iterator> iterator(){
                return new EntryIterator();
            }
    
            @Override
            public int size(){
                return this.keys.size();
            }
            @Override
            public boolean remove(Object o) {
                return keys.remove(o);
            }
    
        }
    
        private final WeakHashMap cache;
        private final Set> entries;
        private final Function funk;
    
        public SetBackedMap(final Set keys, final Function funk){
            this.funk = funk;
            this.cache = new WeakHashMap();
            this.entries = new EntrySet(keys);
        }
    
        @Override
        public Set> entrySet(){
            return this.entries;
        }
    
        public boolean putKey(K key){
            return entries.add(new MapEntry(key));
        }
    
        @Override
        public boolean removeKey(K key) {
            cache.remove(key);
            return entries.remove(key);
        }
    
    
    }
    

    Interface SetFunctionMap:

    public interface SetFunctionMap extends Map{
         public boolean putKey(K key);
         public boolean removeKey(K key);
    }
    

    Test Code:

    public class SetBackedMapTst {
    public static void main(String[] args) {
        Set set=new TreeSet(Arrays.asList(
                1, 2, 4, 8, 16));
        final SetFunctionMap map =
            new SetBackedMap(set,
                new Function(){
                    @Override
                    public String apply(final Integer from){
                        return Integer.toBinaryString(from.intValue());
                    }
                });
              set.add(222);
              System.out.println("Map: "+map); 
              System.out.println("Set: "+set);
              map.putKey(112);
              System.out.println("Map: "+map); 
              System.out.println("Set: "+set);
              map.removeKey(112);
              System.out.println("Map: "+map); 
              System.out.println("Set: "+set);
    
    }
    }
    

    Output:

    Map: {1=1, 2=10, 4=100, 8=1000, 16=10000, 222=11011110}//change to set reflected in map 
    Set: [1, 2, 4, 8, 16, 222]
    Map: {1=1, 2=10, 4=100, 8=1000, 16=10000, 112=1110000, 222=11011110}
    Set: [1, 2, 4, 8, 16, 112, 222]//change to map reflected in set 
    Map: {1=1, 2=10, 4=100, 8=1000, 16=10000, 222=11011110}
    Set: [1, 2, 4, 8, 16, 222]//change to map reflected in set 
    

提交回复
热议问题