java - 如何使用 Guava 将列表 A、B 转换为元组的键控映射

标签 java functional-programming guava

如果这个问题是重复的,我深表歉意,搜索很困难,因为我不确定我要完成的事情的正确名称。最简单的解释是

List<A>, List<B> into Map<Key, Tuple<A,B>> where A.Key matched B.Key

澄清一下:我有一个共享 key 的 A 对象和 B 对象的列表。然后我想将这两个列表关联到一个映射中,其中键匹配到键映射和元组 A、B。

我在脑海中想出了很多关于如何做到这一点的想法,但大多数想法最终都让我觉得我误用了库(例如 Maps.uniqueIndex 和 Iterables.transform)。谁能指出我正确的方向?

最佳答案

Guava 中没有元组(对等)实现。 (如果用 Java 实现元组是个好主意,这是另一个讨论。)我建议的自然映射是使用 Multimap:

List<A> as = Lists.newArrayList(new A(1, "a"), new A(3, "c"), new A(2, "b"));
List<B> bs = Lists.newArrayList(new B(1, 2), new B(3, 6), new B(5, 10));

Function<WithKey, Object> toKey = new Function<WithKey, Object>() {
    @Override public Object apply(WithKey input) { return input.key(); }
};
ImmutableListMultimap<Object, AbstractWithKey> index = 
    Multimaps.index(Iterables.concat(as, bs), toKey);

Multimap<Object, WithKey> m = ArrayListMultimap.create();
for (WithKey w : Iterables.concat(as, bs)) m.put(w.key(), w);

您必须在使用多图之前(或在遍历多图条目时)检查不变量,例如,可能存在只有 A 或 B 实例的键。 (这不应该是一个性能问题,因为它可以通过 Iterables.filter 懒惰地完成。)

一种类型的重复是另一个问题。您可以检查它们或使用 HashMultimap 忽略它们。您甚至可以构建一个包含值约束集的多重映射,以检查值是否唯一(请参阅 Multimaps.newSetMultimap(Map> map, Supplier> factory)Constraints.constrainedSet(Set set, Constraint constraint) )。这具有快速失败的优点。

有了这些 A 和 B 实现:

interface WithKey {
    Object key();
}
abstract class AbstractWithKey implements WithKey {
    Object key;
    Object v;
    @Override public Object key() { return key; }
    @Override public String toString() { 
        return MoreObjects.toStringHelper(this).add("k", key).add("v", v).toString(); 
    }
}
class A extends AbstractWithKey {
    public A(int i, String v) { 
        key = i;
        this.v = v;
    } 
}
class B extends AbstractWithKey {
    public B(int i, int v) { 
        key = i;
        this.v = v;
    }
}

输出是:

{1=[A{k=1, v=a}, B{k=1, v=2}], 2=[A{k=2, v=b}], 3=[A{k=3, v=c}, B{k=3, v=6}], 5=[B{k=5, v=10}]}

更新:

如果您必须以元组实例结束,您可以转换 Multimap。

Multimap<Object, WithKey> m = ArrayListMultimap.create(); 
for (WithKey w : Iterables.concat(as, bs)) m.put(w.key(), w);

Function<Collection<WithKey>, Tuple> f = 
    new Function<Collection<WithKey>, Tuple>(){
    @Override public Tuple apply(Collection<WithKey> input) {
        Iterator<WithKey> iterator = input.iterator();
        return new Tuple(iterator.next(), iterator.next());
    } };
Map<Object, Tuple> result = Maps.transformValues(m.asMap(), f);

输出((a,b)是元组语法):

{1=(A{k=1, v=a},B{k=1, v=2}), 3=(A{k=3, v=c},B{k=3, v=6})}

关于java - 如何使用 Guava 将列表 A、B 转换为元组的键控映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8830033/

相关文章:

list - 为什么 Haskell 允许 Shape 列表,但不允许 Square 或 Circle 或 Triangle 列表

java - 为什么使用工厂方法时 TypeToken 无法捕获泛型类型?

java - Guava 中 ForwardingMap 的用途是什么?

functional-programming - Common LISP 传递的参数少于所需的参数 - 这是怎么回事?

haskell - 描述给定 foldr 函数的前几个评估步骤

java - 将 Guava 的 Optional 与 @XmlAttribute 一起使用

java - 在抽象访问的同时访问数据库中数据的最佳实践

java - 如何在功能接口(interface)/lambda 调用中传递 Object 对象

java - int 和 Integer 的不同行为

java - 找不到标志