Java:如何在不迭代的情况下从 List<T> 转换为 Map<f1(T), List(f2(T))>

标签 java collections guava lambdaj

我有一个对象列表,我需要将其转换为映射,其中键是每个元素的函数,值是每个元素的另一个函数的列表。实际上,这是根据元素的功能对元素进行分组。

例如,假设一个简单的元素类:

class Element {
    int f1() { ... }
    String f2() { ... }
}

以及这些的列表:

[
    { f1=100, f2="Alice" },
    { f1=200, f2="Bob" },
    { f1=100, f2="Charles" },
    { f1=300, f2="Dave" }
]

那么我想要一张 map 如下:

{
    {key=100, value=[ "Alice", "Charles" ]},
    {key=200, value=[ "Bob" ]},
    {key=300, value=[ "Dave" ]}
}

谁能建议一种在 Java 中无需迭代的简洁方法? LambdaJ 的 group 方法与 Guava 的 Maps.transform 的组合几乎可以达到目的,但 group 不会生成 map 。

最佳答案

Guava 有 Maps.uniqueIndex(Iterable values, Function keyFunction)Multimaps.index(Iterable values, Function keyFunction) ,但它们不会转换值。有some requests添加实用方法来执行您想要的操作,但现在,您必须使用 Multimaps.index() 和 Multimaps.transformValues() 自己滚动它:

static class Person {
    private final Integer age;
    private final String name;

    public Person(Integer age, String name) {
        this.age = age;
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public String getName() {
        return name;
    }
}

private enum GetAgeFunction implements Function<Person, Integer> {
    INSTANCE;

    @Override
    public Integer apply(Person person) {
        return person.getAge();
    }
}

private enum GetNameFunction implements Function<Person, String> {
    INSTANCE;

    @Override
    public String apply(Person person) {
        return person.getName();
    }
}

public void example() {
    List<Person> persons = ImmutableList.of(
            new Person(100, "Alice"),
            new Person(200, "Bob"),
            new Person(100, "Charles"),
            new Person(300, "Dave")
    );

    ListMultimap<Integer, String> ageToNames = getAgeToNamesMultimap(persons);

    System.out.println(ageToNames);

    // prints {100=[Alice, Charles], 200=[Bob], 300=[Dave]}
}

private ListMultimap<Integer, String> getAgeToNamesMultimap(List<Person> persons) {
    ImmutableListMultimap<Integer, Person> ageToPersons = Multimaps.index(persons, GetAgeFunction.INSTANCE);
    ListMultimap<Integer, String> ageToNames = Multimaps.transformValues(ageToPersons, GetNameFunction.INSTANCE);

    // Multimaps.transformValues() returns a *lazily* transformed view of "ageToPersons"
    // If we want to iterate multiple times over it, it's better to create a copy
    return ImmutableListMultimap.copyOf(ageToNames);
}

可重用的实用方法可以是:

public static <E, K, V> ImmutableListMultimap<K, V> keyToValuesMultimap(Iterable<E> elements, Function<E, K> keyFunction, Function<E, V> valueFunction) {
    ImmutableListMultimap<K, E> keysToElements = Multimaps.index(elements, keyFunction);
    ListMultimap<K, V> keysToValuesLazy = Multimaps.transformValues(keysToElements, valueFunction);
    return ImmutableListMultimap.copyOf(keysToValuesLazy);
}

我想我们可以通过使用 Function<? extends E, K> 改进签名中的泛型之类的,但我没有时间深入研究...

关于Java:如何在不迭代的情况下从 List<T> 转换为 Map<f1(T), List(f2(T))>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8354200/

相关文章:

java - 使用 Guava 连接 ImmutableSet

java - JSP IllegalArgumentException : com. sun.xml.messaging.saaj.soap.LocalString!= com.sun.xml.internal.messaging.saaj.soap.LocalStrings问题

java - request.getRemoteAddr() 返回 0 :0:0:0:0:0:0:1 in JSP page

java - 文件对象和不同的 NetBeans 包

java - Guava的AbstractExecutionThreadService可以复用吗?

java - Guava 缓存 RemovalListener 未调用

java - 在Java中为当前时间添加一个大时间戳

python - 如何在Python中使用集合中的Counter来计算不同列表中的单词数?

java - 允许多种预定义类型的集合

java - 如何获取数组列表中的 HashMap 的克隆