要设置的Java映射?有没有一种方法可以实现预先存在的java库,以允许将集合作为值包含在映射中?

要设置的Java映射?有没有一种方法可以实现预先存在的java库,以允许将集合作为值包含在映射中?,java,generics,set,Java,Generics,Set,我试图创建id号和集合值的键,但我还需要编写对那些固定在值中的集合进行迭代(需要Iterable,因此我尝试使用集合)的通用方法。什么是对作为映射对象一部分的某些通用值实现迭代器的有效方法?您所描述的映射通常被称为“基于集合的多重映射” 这种映射的一种流行实现是 使用这样的映射,其values()将返回一个集合,该集合将包含Y的所有值(而不是所有Set实例) 可以使用基本映射“手工”实现这样一个集合,但事实证明,要在所有用例中正确地实现并保留Java Collections框架语义是非常困难的。

我试图创建id号和集合值的键,但我还需要编写对那些固定在值中的集合进行迭代(需要Iterable,因此我尝试使用集合)的通用方法。什么是对作为映射对象一部分的某些通用值实现迭代器的有效方法?

您所描述的映射通常被称为“基于集合的多重映射”

这种映射的一种流行实现是

使用这样的映射,其
values()
将返回一个集合,该集合将包含
Y
的所有值(而不是所有
Set
实例)

可以使用基本映射“手工”实现这样一个集合,但事实证明,要在所有用例中正确地实现并保留Java Collections框架语义是非常困难的。因此,使用库的实现通常是可行的

另一个选项是使用流API(Java8),使用诸如
groupBy
之类的收集器来构建映射实例,并使用其他流操作在需要迭代映射值时“展平”映射值(参见示例)

下面,查找SetMultiMap代码示例

public static void main(String[] args) {

Multimap<Integer, String> multiMap = HashMultimap.create();
multiMap.put(0, "key0_value0");
// Twice the same value for the same key, the Set<String> will "ignore" this
multiMap.put(0, "key0_value0"); 
multiMap.put(1, "key1_value0"); 
multiMap.put(1, "key1_value1"); 


System.out.println("Values for key 0");
System.out.println("----------------");
System.out.println(multiMap.get(0));
System.out.println("\r\nValues for key 1");
System.out.println("----------------");
System.out.println(multiMap.get(1));
System.out.println("\r\nAll values");
System.out.println("------------");
System.out.println(multiMap.values());

// Entries are all Integer/String associations
Collection<Entry<Integer, String>> entries = multiMap.entries();
System.out.println("\r\nNumber of entries : " + entries.size());

// We can build a standard Java Map out of the Multimap
Map<Integer, Collection<String>> realJavaMap = multiMap.asMap();
// The map's values are actually guaranteed to be Sets
System.out.println("Multimap as Map, values implement Set : " + Set.class.isAssignableFrom(realJavaMap.values().iterator().next().getClass()));

// The java Map is a live view of the multimap
realJavaMap.get(0).add("key0_value1"); // Actions on realJavaMap will update multimap

System.out.println("\r\nValues for key 0");
System.out.println("----------------");
System.out.println(multiMap.get(0));

您所描述的
映射
,通常被称为“基于集合的多重映射”

这种映射的一种流行实现是

使用这样的映射,其
values()
将返回一个集合,该集合将包含
Y
的所有值(而不是所有
Set
实例)

可以使用基本映射“手工”实现这样一个集合,但事实证明,要在所有用例中正确地实现并保留Java Collections框架语义是非常困难的。因此,使用库的实现通常是可行的

另一个选项是使用流API(Java8),使用诸如
groupBy
之类的收集器来构建映射实例,并使用其他流操作在需要迭代映射值时“展平”映射值(参见示例)

下面,查找SetMultiMap代码示例

public static void main(String[] args) {

Multimap<Integer, String> multiMap = HashMultimap.create();
multiMap.put(0, "key0_value0");
// Twice the same value for the same key, the Set<String> will "ignore" this
multiMap.put(0, "key0_value0"); 
multiMap.put(1, "key1_value0"); 
multiMap.put(1, "key1_value1"); 


System.out.println("Values for key 0");
System.out.println("----------------");
System.out.println(multiMap.get(0));
System.out.println("\r\nValues for key 1");
System.out.println("----------------");
System.out.println(multiMap.get(1));
System.out.println("\r\nAll values");
System.out.println("------------");
System.out.println(multiMap.values());

// Entries are all Integer/String associations
Collection<Entry<Integer, String>> entries = multiMap.entries();
System.out.println("\r\nNumber of entries : " + entries.size());

// We can build a standard Java Map out of the Multimap
Map<Integer, Collection<String>> realJavaMap = multiMap.asMap();
// The map's values are actually guaranteed to be Sets
System.out.println("Multimap as Map, values implement Set : " + Set.class.isAssignableFrom(realJavaMap.values().iterator().next().getClass()));

// The java Map is a live view of the multimap
realJavaMap.get(0).add("key0_value1"); // Actions on realJavaMap will update multimap

System.out.println("\r\nValues for key 0");
System.out.println("----------------");
System.out.println(multiMap.get(0));
这似乎有效:

class MapOfSetsIterable<V> implements Iterable<V> {

    private final Map<?, Set<V>> map;

    public MapOfSetsIterable(Map<?, Set<V>> map) {
        this.map = map;
    }

    @Override
    public Iterator<V> iterator() {
        return new MapOfSetsIterator();
    }

    private class MapOfSetsIterator implements Iterator<V> {

        final Iterator<Set<V>> sets = map.values().iterator();
        Iterator<V> i = sets.hasNext() ? sets.next().iterator() : Collections.EMPTY_SET.iterator();
        V next = null;

        @Override
        public boolean hasNext() {
            while (next == null && (sets.hasNext() || i.hasNext())) {
                if (!i.hasNext() && sets.hasNext()) {
                    i = sets.next().iterator();
                }
                if (i.hasNext()) {
                    next = i.next();
                }
            }
            return next != null;
        }

        @Override
        public V next() {
            if (next == null) {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
            }
            V n = next;
            next = null;
            return n;
        }
    }
}

enum E {

    A, B
};

public void test() {
    Map<Integer, Set<E>> map = new HashMap<>();
    map.put(1, EnumSet.of(E.A));
    map.put(2, EnumSet.of(E.B));
    map.put(3, EnumSet.of(E.A, E.B));
    for (E e : new MapOfSetsIterable<>(map)) {
        System.out.println(e);
    }
}
类MapOfSetsIterable实现了Iterable{
私人最终地图这似乎有效:

class MapOfSetsIterable<V> implements Iterable<V> {

    private final Map<?, Set<V>> map;

    public MapOfSetsIterable(Map<?, Set<V>> map) {
        this.map = map;
    }

    @Override
    public Iterator<V> iterator() {
        return new MapOfSetsIterator();
    }

    private class MapOfSetsIterator implements Iterator<V> {

        final Iterator<Set<V>> sets = map.values().iterator();
        Iterator<V> i = sets.hasNext() ? sets.next().iterator() : Collections.EMPTY_SET.iterator();
        V next = null;

        @Override
        public boolean hasNext() {
            while (next == null && (sets.hasNext() || i.hasNext())) {
                if (!i.hasNext() && sets.hasNext()) {
                    i = sets.next().iterator();
                }
                if (i.hasNext()) {
                    next = i.next();
                }
            }
            return next != null;
        }

        @Override
        public V next() {
            if (next == null) {
                if (!hasNext()) {
                    throw new NoSuchElementException();
                }
            }
            V n = next;
            next = null;
            return n;
        }
    }
}

enum E {

    A, B
};

public void test() {
    Map<Integer, Set<E>> map = new HashMap<>();
    map.put(1, EnumSet.of(E.A));
    map.put(2, EnumSet.of(E.B));
    map.put(3, EnumSet.of(E.A, E.B));
    for (E e : new MapOfSetsIterable<>(map)) {
        System.out.println(e);
    }
}
类MapOfSetsIterable实现了Iterable{

private final Map您的意思是:Map myMap=new HashMap();使用流API吗?您可以
Map=Stream.collect(groupingBy(…,toSet())
然后
Map.values().Stream().flatMap(Collection::Stream)
为什么
HashSet
不适合您的需要?是的,我正在尝试Kartic那边的方法。这就是我应该如何设置通用变量的方法吗?这很有意义,因为集合实现了Iterable,所以从技术上讲,任何集合都应该用于遍历和访问其字符串值。我将尝试一下。谢谢。你的意思是什么ke:Map myMap=new HashMap();使用流API?您可以
Map=Stream.collect(groupingBy(…,toSet())
然后
Map.values().Stream().flatMap(Collection::Stream)
为什么
HashSet
不适合您的需要?是的,我正在尝试Kartic那边的方法。这就是我应该如何设置通用变量的方法吗?这很有意义,因为集合实现了Iterable,所以从技术上讲,任何集合都应该用于遍历和访问其字符串值。我将尝试一下。谢谢。我必须声明一个ge吗neric type for hashmap,或者我可以开始使用基本hashmap hm=new HasMap()的方法;我在答案中添加了一个代码示例,以展示基于Guava的解决方案是如何工作的。不幸的是,我现在没有访问Java 8编辑器的权限,因此我现在无法发布基于流API的示例(我可以猜测并生成一个半工作的实现,但它可能不会真正工作)。我必须为hashmap声明一个泛型类型,还是可以开始使用基本hashmap hm=new HasMap()的方法;我在回答中添加了一个代码示例,以展示基于Guava的解决方案是如何工作的。不幸的是,我现在无法访问Java 8编辑器,因此我现在无法发布基于流API的示例(我可以猜测并生成一个半工作的实现,但它可能不会真正工作)。