英文:
Getting multiple list of properties from a List of Objects in Java 8
问题
考虑我有一个对象列表 List<Emp>
,其中 Emp
有3个属性 name
、id
和 age
。如何以最快的方式获得三个列表,分别是 List<String> names
、List<String> ids
和 List<Integer> ages
。
我能想到的最简单方法是遍历整个列表,并将信息添加到这三个列表中。但是,我想知道是否有一种更简便的方法可以在 Java 8 的流(Stream)中完成?
提前感谢。
英文:
Considering I have a list of objects List<Emp>
where Emp
has 3 properties name
, id
, and age
. What is the fastest way to get 3 lists like List<String> names
, List<String> ids
, and List<Integer> ages
.
The simplest I could think of is to iterate over the entire list and keep adding to these 3 lists. But, I was wondering if there is an easier way to do it with Java 8 streams?
Thanks in advance.
答案1
得分: 1
这是一个非常有趣的问题,然而,没有专门的收集器来处理这种用例。
你可以分别使用 3 次迭代(Streams):
List<String> names = employees.stream().map(Emp::name).collect(Collectors.toList());
List<Integer> ids = employees.stream().map(Emp::id).collect(Collectors.toList());
List<Integer> ages = employees.stream().map(Emp::age).collect(Collectors.toList());
编辑 - 编写自己的收集器:你可以使用重载的方法 Stream::collect(Supplier, BiConsumer, BiConsumer)
来实现自己的收集器,执行你需要的操作:
Map<String, List<Object>> newMap = employees.stream().collect(
HashMap::new, // Map 的供应者
(map, emp) -> { // 累加器 BiConsumer
map.compute("names", remappingFunction(emp.getName()));
map.compute("ages", remappingFunction(emp.getAge()));
map.compute("ids", remappingFunction(emp.getId()));
},
(map1, map2) -> {} // 组合器 BiConsumer
);
实际上,它只是提取所需的值(name
、age
等),并将其添加到特定键 names
、ages
等下的 List
中,使用方法 Map::compute
允许根据现有值计算新值(如果键尚未使用,则默认为 null
)。
实际执行添加值或创建新 List
的 remappingFunction
如下:
private static BiFunction<String, List<Object>, List<Object>> remappingFunction(Object object) {
return (key, list) -> {
if (list == null)
list = new ArrayList<>();
list.add(object);
return list;
};
}
英文:
It's a very interesting question, however, there is no dedicated collector to handle such use case.
All you can is to use 3 iterations (Streams) respectively:
List<String> names = employees.stream().map(Emp::name).collect(Collectors.toList());
List<Integer> ids = employees.stream().map(Emp::id).collect(Collectors.toList());
List<Integer> ages = employees.stream().map(Emp::age).collect(Collectors.toList());
Edit - write the own collector: you can use the overloaded method Stream::collect(Supplier, BiConsumer, BiConsumer)
to implement your own collector doing what you need:
Map<String, List<Object>> newMap = employees.stream().collect(
HashMap::new, // Supplier of the Map
(map, emp) -> { // BiConsumer accumulator
map.compute("names", remappingFunction(emp.getName()));
map.compute("ages", remappingFunction(emp.getAge()));
map.compute("ids", remappingFunction(emp.getId()));
},
(map1, map2) -> {} // BiConsumer combiner
);
Practically, all it does is extracting the wanted value (name
, age
...) and adding it to the List
under the specific key "names"
, "ages"
etc. using the method Map::compute
that allows to compute a new value based on the existing (null
by default if the key has not been used).
The remappingFunction
that actually creates a new List
or adds a value looks like:
private static BiFunction<String, List<Object>, List<Object>> remappingFunction(Object object) {
return (key, list) -> {
if (list == null)
list = new ArrayList<>();
list.add(object);
return list;
};
}
答案2
得分: 0
Java 8 Stream中有一些API可以将列表分割成分区,例如:
Collectors.partitioningBy(..)
- 基于某个Predicate
创建两个分区,并返回带有值的Map<Boolean, List<>>
;Collectors.groupingBy()
- 允许按某个键对流进行分组,并返回结果Map。
但是,这实际上不适用于您的情况,因为您想要将Emp
对象的所有属性放入不同的Lists
中。我不确定是否可以通过这种API实现,也许可以使用一些不太正规的方法来实现。
因此,是的,最清晰的方法是通过迭代Emp
列表,并手动将所有属性输出到三个列表中,就像您提出的那样。
英文:
Java 8 Stream has some API to split the list into partition, such as:
Collectros.partitioningBy(..)
- which create two partitions based on somePredicate
and returnMap<Boolean, List<>>
with values;Collectors.groupingBy()
- which allows to group stream by some key and return resulting Map.
But, this is not really your case, since you want to put all properties of the Emp
object to different Lists
. I'm not sure that this can be achieved with such API, maybe with some dirty workarounds.
So, yes, the cleanest way will be to iterate through the Emp
list and out all properties to the three Lists manually, as you have proposed.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论