Java:如何在没有迭代的情况下从List 转换为Map

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

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

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

以及这些的清单:

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

那我想要一张如下地图:

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

任何人都可以在没有迭代的情况下在Java中建议一种简洁的方法吗? LambdaJ的group方法与Guava的Maps.transformMaps.transform几乎可以实现,但是group不会生成地图。

Guava有Maps.uniqueIndex(Iterable values,Function keyFunction)和Multimaps.index(Iterable values,Function keyFunction) ,但它们不会转换值。 有一些 要求添加实用程序方法可以执行您想要的操作,但是现在,您必须使用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 { INSTANCE; @Override public Integer apply(Person person) { return person.getAge(); } } private enum GetNameFunction implements Function { INSTANCE; @Override public String apply(Person person) { return person.getName(); } } public void example() { List persons = ImmutableList.of( new Person(100, "Alice"), new Person(200, "Bob"), new Person(100, "Charles"), new Person(300, "Dave") ); ListMultimap ageToNames = getAgeToNamesMultimap(persons); System.out.println(ageToNames); // prints {100=[Alice, Charles], 200=[Bob], 300=[Dave]} } private ListMultimap getAgeToNamesMultimap(List persons) { ImmutableListMultimap ageToPersons = Multimaps.index(persons, GetAgeFunction.INSTANCE); ListMultimap 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  ImmutableListMultimap keyToValuesMultimap(Iterable elements, Function keyFunction, Function valueFunction) { ImmutableListMultimap keysToElements = Multimaps.index(elements, keyFunction); ListMultimap keysToValuesLazy = Multimaps.transformValues(keysToElements, valueFunction); return ImmutableListMultimap.copyOf(keysToValuesLazy); } 

我想我们可以通过使用Function来改进签名中的genericsFunction Function或其他什么,但我没有时间深入研究……

现在使用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 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+"}")); } 

有一些讨论在Apache的CollectionUtils中添加一个API来将List转换为Map,但后来我没有看到任何不使用foreach contruct的原因,你有什么问题吗? 变换将做同样的事情,你可以通过foreach轻松获得,循环无法避免。

编辑:

以下是Apache论坛http://apache-commons.680414.n4.nabble.com/Convert-List-to-Map-td747218.html中讨论的链接

我不知道你为什么不想迭代。 JDK不支持转换,但您可以自己实现它。

如果你担心性能,即使JDK支持它,它也会迭代它。