Guava:设置< K> +函数< K,V> = Map< K,V>? [英] Guava: Set<K> + Function<K,V> = Map<K,V>?

查看:183
本文介绍了Guava:设置< K> +函数< K,V> = Map< K,V>?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有一个惯用的方法来取 Set< K> Function< K,V> 并获得地图< K,V> 实时取景? (即 Map Set Function 组合,并且如果例如将一个元素添加到 Set 中,则相应的条目也存在于 Map 中)。

Is there an idiomatic way to take a Set<K> and a Function<K,V>, and get a Map<K,V> live view? (i.e. the Map is backed by the Set and Function combo, and if e.g. an element is added to the Set, then the corresponding entry also exists in the Map).

(请参阅 Collections2.filter 了解更多有关直播的讨论视图)

(see e.g. Collections2.filter for more discussion on live views)

如果不需要实时视图会怎么样?有比这更好的东西:

What if a live view is not needed? Is there something better than this:

public static <K,V> Map<K,V> newMapFrom(Set<K> keys, Function<? super K,V> f) {
    Map<K,V> map = Maps.newHashMap();
    for (K k : keys) {
        map.put(k, f.apply(k));
    }
    return map;
}


推荐答案

和一个函数



这里有两个类,每个都应该做这个工作。第一个只显示集合的地图视图,第二个可以通过一个特殊的接口将值写回集合。

Creating a Map from a Set and a Function

Here are two classes that should each do the job. The first just shows a map view of the set, while the second can write values back to the set through a special interface.

调用语法:

Map<K,V> immutable = new SetBackedMap<K,V>(Set<K> keys, Function<K,V> func);
Map<K,V> mutable = new MutableSetBackedMap<K,V>(Set<K> keys, Function<K,V> func);






何处放置此代码?



注意:如果番石榴是我的图书馆,我可以通过地图类别:

Map<K,V> immutable = Maps.immutableComputingMap(Set<K> keys, Function<K,V> func);
Map<K,V> mutable = Maps.mutableComputingMap(Set<K> keys, Function<K,V> func);






不可更改的版本:



我已将此实现为单向视图:


Immutable version:

I have implemented this as a one-way view:


  • 对集合的更改反映在
    的映射,但不是反过来(你不能改变地图, put(key,value)方法没有实现)。 li>
  • entrySet()迭代器在内部使用
    集合迭代器,因此
    也会继承内部迭代器
    处理
    ConcurrentModificationException

  • put(k,v) code>和
    entrySet()。iterator()。remove()
    throw
    UnsupportedOperationException

  • 值缓存在 WeakHashMap
    中,即在
    任何级别上没有同步。这在大多数情况下会做,但如果你的功能很贵,你可能想要添加一些锁。

  • Changes to the set are reflected in the map, but not vice-versa (and you can't change the map anyway, the put(key, value) method isn't implemented).
  • The entrySet() iterator uses the set iterator internally, so it will also inherit the internal iterator's handling of ConcurrentModificationException.
  • Both put(k,v) and entrySet().iterator().remove() will throw UnsupportedOperationException.
  • Values are cached in a WeakHashMap, with no special concurrency handling, i.e. there is no synchronization at any level. This will do for most cases, but if your function is expensive, you might want to add some locking.

public class SetBackedMap<K, V> extends AbstractMap<K, V>{

    private class MapEntry implements Entry<K, V>{
        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();
        }
    }

    private class EntrySet extends AbstractSet<Entry<K, V>>{

        public class EntryIterator implements Iterator<Entry<K, V>>{
            private final Iterator<K> inner;
            public EntryIterator(){
                this.inner = EntrySet.this.keys.iterator();
            }
            @Override
            public boolean hasNext(){
                return this.inner.hasNext();
            }
            @Override
            public Map.Entry<K, V> next(){
                final K key = this.inner.next();
                return new MapEntry(key);
            }
            @Override
            public void remove(){
                throw new UnsupportedOperationException();
            }
        }

        private final Set<K> keys;

        public EntrySet(final Set<K> keys){
            this.keys = keys;
        }

        @Override
        public Iterator<Map.Entry<K, V>> iterator(){
            return new EntryIterator();
        }

        @Override
        public int size(){
            return this.keys.size();
        }

    }

    private final WeakHashMap<K, V> cache;
    private final Set<Entry<K, V>> entries;
    private final Function<? super K, ? extends V> funk;

    public SetBackedMap(
        final Set<K> keys, Function<? super K, ? extends V> funk){
        this.funk = funk;
        this.cache = new WeakHashMap<K, V>();
        this.entries = new EntrySet(keys);
    }

    @Override
    public Set<Map.Entry<K, V>> entrySet(){
        return this.entries;
    }

}

strong>

Test:

final Map<Integer, String> map =
    new SetBackedMap<Integer, String>(
        new TreeSet<Integer>(Arrays.asList(
            1, 2, 4, 8, 16, 32, 64, 128, 256)),
        new Function<Integer, String>(){

            @Override
            public String apply(final Integer from){
                return Integer.toBinaryString(from.intValue());
            }
        });
for(final Map.Entry<Integer, String> entry : map.entrySet()){
    System.out.println(
        "Key: " + entry.getKey()
        + ", value: " + entry.getValue());
}

输出

Key: 1, value: 1
Key: 2, value: 10
Key: 4, value: 100
Key: 8, value: 1000
Key: 16, value: 10000
Key: 32, value: 100000
Key: 64, value: 1000000
Key: 128, value: 10000000
Key: 256, value: 100000000






< h2> Mutable版本:

虽然我认为这是一个单向的好主意,这里有一个Emil的版本提供了一个双向视图的Emil的我的解决方案的变化:-))。它需要一个扩展的映射接口,我将调用 ComputingMap 清楚地表明这是一个映射,它没有意义调用 put键,值)


Mutable Version:

While I think it's a good idea to make this one-way, here's a version for Emil that provides a two-way view (it's a variation of Emil's variation of my solution :-)). It requires an extended map interface that I'll call ComputingMap to make clear that this is a map where it doesn't make sense to call put(key, value).

地图界面

public interface ComputingMap<K, V> extends Map<K, V>{
    boolean removeKey(final K key);
    boolean addKey(final K key);
}

地图实施:
$ b

Map implementation:

public class MutableSetBackedMap<K, V> extends AbstractMap<K, V> implements
    ComputingMap<K, V>{

    public class MapEntry implements Entry<K, V>{

        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 = MutableSetBackedMap.this.cache.get(this.key);
            if(value == null){
                value = MutableSetBackedMap.this.funk.apply(this.key);
                MutableSetBackedMap.this.cache.put(this.key, value);
            }
            return value;
        }

        @Override
        public V setValue(final V value){
            throw new UnsupportedOperationException();
        }

    }

    public class EntrySet extends AbstractSet<Entry<K, V>>{

        public class EntryIterator implements Iterator<Entry<K, V>>{

            private final Iterator<K> inner;

            public EntryIterator(){
                this.inner = MutableSetBackedMap.this.keys.iterator();
            }

            @Override
            public boolean hasNext(){
                return this.inner.hasNext();
            }

            @Override
            public Map.Entry<K, V> next(){
                final K key = this.inner.next();
                return new MapEntry(key);
            }

            @Override
            public void remove(){
                throw new UnsupportedOperationException();
            }

        }

        public EntrySet(){
        }

        @Override
        public Iterator<Map.Entry<K, V>> iterator(){
            return new EntryIterator();
        }

        @Override
        public int size(){
            return MutableSetBackedMap.this.keys.size();
        }

    }

    private final WeakHashMap<K, V> cache;
    private final Set<Entry<K, V>> entries;
    private final Function<? super K, ? extends V> funk;
    private final Set<K> keys;

    public MutableSetBackedMap(final Set<K> keys,
        final Function<? super K, ? extends V> funk){
        this.keys = keys;
        this.funk = funk;
        this.cache = new WeakHashMap<K, V>();
        this.entries = new EntrySet();
    }

    @Override
    public boolean addKey(final K key){
        return this.keys.add(key);
    }

    @Override
    public boolean removeKey(final K key){
        return this.keys.remove(key);
    }

    @Override
    public Set<Map.Entry<K, V>> entrySet(){
        return this.entries;
    }

}

strong>

Test:

public static void main(final String[] args){
    final ComputingMap<Integer, String> map =
        new MutableSetBackedMap<Integer, String>(
            new TreeSet<Integer>(Arrays.asList(
                1, 2, 4, 8, 16, 32, 64, 128, 256)),
            new Function<Integer, String>(){

                @Override
                public String apply(final Integer from){
                    return Integer.toBinaryString(from.intValue());
                }
            });
    System.out.println(map);
    map.addKey(3);
    map.addKey(217);
    map.removeKey(8);
    System.out.println(map);
}

输出

{1=1, 2=10, 4=100, 8=1000, 16=10000, 32=100000, 64=1000000, 128=10000000, 256=100000000}
{1=1, 2=10, 3=11, 4=100, 16=10000, 32=100000, 64=1000000, 128=10000000, 217=11011001, 256=100000000}

这篇关于Guava:设置&lt; K&gt; +函数&lt; K,V&gt; = Map&lt; K,V&gt;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆