Java:如何从List&lt; T&gt;到映射<f1(T),列表(f2(T))>无需迭代 [英] Java: how to transform from List&lt;T&gt; to Map&lt;f1(T), List(f2(T))&gt; without iterating

查看:172
本文介绍了Java:如何从List&lt; T&gt;到映射<f1(T),列表(f2(T))>无需迭代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个对象列表,我需要转换到一个映射,其中键是每个元素的函数,值是每个元素的另一个函数的列表。实际上,这是通过它们的函数将元素分组。



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



< p $ p> class Element {
int f1(){...}
String f2(){...}
}

以及以下列表:

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

然后我想要一个地图如下:

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

任何人都可以提出一个简单的方法,在Java 中执行此操作而不重复? LambdaJ的方法与Guava的 Maps.transform 的组合几乎可以实现,但 / code>不生成地图。

解决方案

Guava具有 Maps.uniqueIndex(可迭代值,Function keyFunction)Multimaps.index(Iterable values,Function keyFunction),但他们不会t变换值。有一些 请求添加实用工具方法,但是现在,你必须使用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> {
IN STANCE;

@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 ImmutableListMultimap< Integer,Person> ageToPersons = Multimaps.index(persons,GetAgeFunction.INSTANCE);
ListMultimap< Integer,String> ageToNames = Multimaps.transformValues(ageToPersons,GetNameFunction.INSTANCE);

// Multimaps.transformValues()返回ageToPersons的一个* lazily *转换视图
//如果我们想要遍历它多次,最好创建一个副本
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);
}



我想我们可以通过使用<$ c $来改进签名中的泛型c> Function<?扩展E,K>
或某事,但我没有时间进一步探索...


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? A combination of LambdaJ's group method with Guava's Maps.transform nearly gets there, but group doesn't generate a map.

解决方案

Guava has Maps.uniqueIndex(Iterable values, Function keyFunction) and Multimaps.index(Iterable values, Function keyFunction), but they don't transform the values. 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():

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> or something, but I don't have the time to delve further...

这篇关于Java:如何从List&lt; T&gt;到映射<f1(T),列表(f2(T))>无需迭代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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