Java 8 对象列表映射<String, List> 值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/50348166/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8 List of Objects to Map<String, List> of values
提问by Rinsen S
I am trying to convert List<Object>
to Map<String, List>
using Streams
,
我正在尝试转换List<Object>
为Map<String, List>
使用Streams
,
public class User{
String name;
String age;
String org;
}
I have List<Users>
, and need to collect into Map<String, Object> m
,
我有List<Users>
,需要收集到Map<String, Object> m
,
m.put("names", List of names,);
m.put("age", List of age);
m.put("org", List of org);
to be use in named query -> eg: select * from table ... where names in (:names) and age in (:age) and org in (:org)
用于命名查询 -> 例如: select * from table ... where names in (:names) and age in (:age) and org in (:org)
as of now I am doing like
到目前为止,我正在做
List<String> names = userList.stream().map(User::getName).collect(Collectors.toList());
List<String> age= userList.stream().map(User::getAge).collect(Collectors.toList());
List<String> org= userList.stream().map(User::getName).collect(Collectors.toList());
How to collect all the values while streaming to the list only once ?
如何在仅流式传输到列表一次时收集所有值?
采纳答案by Eran
I believe something like this should work:
我相信这样的事情应该有效:
Map<String,List<String>> map =
userList.stream()
.flatMap(user -> {
Map<String,String> um = new HashMap<>();
um.put("names",user.getName());
um.put("age",user.getAge());
um.put("org",user.getOrg());
return um.entrySet().stream();
}) // produces a Stream<Map.Entry<String,String>>
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())));
It converts each User
to a Map<String,String>
(containing the 3 required properties indexed by the required keys), and then groups the entries of all the user maps by their keys.
它将每个转换User
为 a Map<String,String>
(包含由所需键索引的 3 个必需属性),然后按其键对所有用户映射的条目进行分组。
EDIT:
编辑:
Here's another alternative that creates the Map.Entry
s directly instead of creating the small HashMap
s, so it should be more efficient:
这是另一种Map.Entry
直接创建s 而不是创建小HashMap
s 的替代方法,因此它应该更有效:
Map<String,List<String>> map =
userList.stream()
.flatMap (user -> Stream.of (new SimpleEntry<>("names",user.getName()),
new SimpleEntry<>("age",user.getAge()),
new SimpleEntry<>("org",user.getOrg())))
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue,
Collectors.toList())));
回答by Michael
Eran's showed youhow you can accomplish this with streams. As you can hopefully see, it's incredibly ugly.
Eran 向您展示了如何使用流来实现这一点。正如你所希望的那样,它非常丑陋。
If your issue with your procedural version is the amount of code duplication, there are other ways besides streams that we can use to solve that problem.
如果您的程序版本问题是代码重复的数量,那么除了流之外,我们还可以使用其他方法来解决该问题。
I would refactor the collection to its own method:
我会将集合重构为它自己的方法:
private static List<String> getProperty(List<User> users, Function<User, String> getter) {
return users.stream().map(getter).collect(Collectors.toList());
}
Map<String,List<String>> map = new HashMap<>();
map.put("names", getProperty(userList, User::getName));
map.put("age", getProperty(userList, User::getAge));
map.put("org", getProperty(userList, User::getOrg));
回答by YCF_L
Generic Solution
通用解决方案
Both @Eran and @Michael gives a nice solution, I would like to solve your problem with a generic way :
@Eran 和 @Michael 都提供了一个很好的解决方案,我想用通用的方式解决您的问题:
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
List<User> listUsers = ...
//Create a List which hold name of field and its value
List<Map<String, Object>> listMapping = new ArrayList<>();
for (User user : listUsers) {
listMapping.add(fieldNameValue(user));
}
//Here group by the name of the field
Map<String, List<Object>> result = listMapping.stream()
.flatMap(a -> a.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.mapping(Map.Entry::getValue, Collectors.toList())));
}
//This method return a Map which hold names of attributes and its values.
static Map<String, Object> fieldNameValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
Map<String, Object> mapping = new HashMap<>();
for (Field field : obj.getClass().getDeclaredFields()) {
field.setAccessible(true);
mapping.put(field.getName(), field.get(obj));
}
return mapping;
}
In this solution you don't care about the number of fields of the type.
在此解决方案中,您不关心类型字段的数量。
回答by JavaHelper
Try this one. Color bean used to separating map value and key from the list.
试试这个。用于从列表中分离映射值和键的颜色 bean。
List<Color> colors = new ArrayList<Color>();
colors.add(new Color("RED", "#FF0000"));
colors.add(new Color("BLUE", "#0000FF"));
colors.add(new Color("GREEN", "#008000"));
// construct key-value pairs from name and code fields of Color
Map<String, String> map = colors.stream()
.collect(Collectors.toMap(Color::getName,
Color::getCode));