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.transform
的Maps.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 extends E, K>
来改进签名中的genericsFunction extends E, K>
Function extends E, K>
或其他什么,但我没有时间深入研究……
现在使用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支持它,它也会迭代它。
- 从内存分配角度看ArrayList与LinkedList
- 为什么LinkedList和arraylist在java中扩展AbstractList?
- LinkedList:Collections.max()抛出NoSuchElementException
- JdbcTemplate IN子句用于String元素
- 通过Collections.synchronizedSet(…)。forEach()的迭代是否保证是线程安全的?
- HashSet与ArrayList
- java concurrent Array List访问
- 如何在Java列表中获得反向列表视图?
- 如何在没有ConcurrentModificationException的情况下对Collection 进行交互并修改其项目?