简体   繁体   English

Java:如何从List <T>转换为Map <f1(T),List(f2(T))>而无需迭代

[英]Java: how to transform from List<T> to Map<f1(T), List(f2(T))> without iterating

I have a list of objects that I need to transform to a map where the keys are a function of each element, and the values are lists of another function of each element. 我有一个对象列表,我需要转换为一个映射,其中键是每个元素的函数,值是每个元素的另一个函数的列表。 Effectively this is grouping the elements by a function of them. 实际上,这是通过它们的功能对元素进行分组。

For example, suppose a simple element class: 例如,假设一个简单的元素类:

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

and a list of these: 以及这些的清单:

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

then I would like a map as follows: 那我想要一张地图如下:

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

Can anyone suggest a succinct way of doing this in Java without iterating ? 任何人都可以建议一种简洁的方式在Java中执行此操作而不进行迭代吗? A combination of LambdaJ's group method with Guava's Maps.transform nearly gets there, but group doesn't generate a map. LambdaJ的group方法与Guava的Maps.transformMaps.transform几乎可以实现,但是group不会生成地图。

Guava has Maps.uniqueIndex(Iterable values, Function keyFunction) and Multimaps.index(Iterable values, Function keyFunction) , but they don't transform the values. Guava有Maps.uniqueIndex(Iterable values,Function keyFunction)Multimaps.index(Iterable values,Function keyFunction) ,但它们不会转换值。 There are some requests to add utility methods that do what you want, but for now, you'll have to roll it yourself using Multimaps.index() and Multimaps.transformValues(): 有些 请求要添加实用程序方法来执行您想要的操作,但是现在,您必须使用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);
}

A re-usable utility method could be: 可重用的实用方法可以是:

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);
}

I guess we could improve the generics in the signature by using Function<? extends E, K> 我想我们可以使用Function<? extends E, K>来改进签名中的泛型Function<? extends E, K> Function<? extends E, K> or something, but I don't have the time to delve further... Function<? extends E, K>或其他什么,但我没有时间深入研究......

Now with Java8 you can do it like: 现在使用Java8,您可以这样做:

static class Element {
    final int f1;
    final String f2;

    Element(int f1, String f2) {
        this.f1 = f1;
        this.f2 = f2;
    }

    int f1() { return f1;}
    String f2() { return f2; }
}

public static void main(String[] args) {
    List<Element> elements = new ArrayList<>();
    elements.add(new Element(100, "Alice"));
    elements.add(new Element(200, "Bob"));
    elements.add(new Element(100, "Charles"));
    elements.add(new Element(300, "Dave"));

    elements.stream()
            .collect(Collectors.groupingBy(
                    Element::f1,
                    Collectors.mapping(Element::f2, Collectors.toList())
                    ))
            .forEach((f1, f2) -> System.out.println("{"+f1.toString() + ", value="+f2+"}"));
}

There has been some discussion in adding one API in Apache's CollectionUtils to transform a List to Map, but then I dont see any reason for not using a foreach contruct, Is there any problem that you are facing ? 有一些讨论在Apache的CollectionUtils中添加一个API来将List转换为Map,但后来我没有看到任何不使用foreach contruct的原因,你有没有遇到任何问题? Transform will do the same thing which you can get easily by foreach, looping cannot be avoided. 变换将做同样的事情,你可以通过foreach轻松获得,循环无法避免。

EDIT: 编辑:

Here is the link to discussion in Apache's forum http://apache-commons.680414.n4.nabble.com/Convert-List-to-Map-td747218.html 以下是Apache论坛http://apache-commons.680414.n4.nabble.com/Convert-List-to-Map-td747218.html中讨论的链接

I don't know why you don't want to iterate. 我不知道你为什么不想迭代。 JDK does not support transform, but you can implement it yourself. JDK不支持转换,但您可以自己实现它。

If you are worried about the performance, even if JDK had supported it, it would have also iterated it. 如果您担心性能,即使JDK支持它,它也会迭代它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 转换清单 <T> 用元素列表进行映射(映射 <F<T> 清单 <T> &gt;)Java 7 - Transform List<T> to Map with List of Elements (Map<F<T>, List<T>>) Java 7 是<T>列表<? extends T> f() 一个有用的签名 - Is <T> List<? extends T> f() a useful signature 如何定义F <T> 和F <T,U> 和F <T,U,V> Java接口? - How to define F<T> and F<T,U> and F<T,U,V> interfaces in Java? JSL中的符号S [F1:= T1,...,Fn:= Tn] - Notation S[F1:=T1,…,Fn:=Tn] in JSL Java流映射T-&gt;?T:List <T> - Java Stream Map T -> ?T:List<T> Java:如何从列表添加对象 <T> 到地图(键:枚举,值列表 <T> ) - Java: How to add objects from List<T> to Map (Key: Enum, value List<T>) 来自java.util.concurrent.Future <T> 播放.libs.F.Promise <T> :如何用Java做到这一点? - From java.util.concurrent.Future<T> to play.libs.F.Promise<T>: How to do that in Java? JLS中f1() + f2()*f3()表达式的执行顺序和运算符优先级 - Execution order of f1() + f2()*f3() expression and operator precedence in JLS 如何转换Observable <Observable<List<T> &gt;&gt;可观察到 <List<T> &gt; - How to Transform Observable<Observable<List<T>>> to Observable<List<T>> 生成一个文件,其内容是 f1 和 f2 的内容副本的串联 - Producing a file whose content is the concatenation of the copies of the contents of f1 and f2
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM