从Java 8中的对象列表中获取多个属性列表。

huangapple go评论79阅读模式
英文:

Getting multiple list of properties from a List of Objects in Java 8

问题

考虑我有一个对象列表 List<Emp>,其中 Emp 有3个属性 nameidage。如何以最快的方式获得三个列表,分别是 List<String> namesList<String> idsList<Integer> ages

我能想到的最简单方法是遍历整个列表,并将信息添加到这三个列表中。但是,我想知道是否有一种更简便的方法可以在 Java 8 的流(Stream)中完成?

提前感谢。

英文:

Considering I have a list of objects List&lt;Emp&gt; where Emp has 3 properties name, id, and age. What is the fastest way to get 3 lists like List&lt;String&gt; names, List&lt;String&gt; ids, and List&lt;Integer&gt; 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
);

实际上,它只是提取所需的值(nameage 等),并将其添加到特定键 namesages 等下的 List 中,使用方法 Map::compute 允许根据现有值计算新值(如果键尚未使用,则默认为 null)。

实际执行添加值或创建新 ListremappingFunction 如下:

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&lt;String&gt; names = employees.stream().map(Emp::name).collect(Collectors.toList());
List&lt;Integer&gt; ids = employees.stream().map(Emp::id).collect(Collectors.toList());
List&lt;Integer&gt; 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&lt;String, List&lt;Object&gt;&gt; newMap = employees.stream().collect(
	HashMap::new,                                               // Supplier of the Map
	(map, emp) -&gt; {                                             // BiConsumer accumulator
		map.compute(&quot;names&quot;, remappingFunction(emp.getName())); 
		map.compute(&quot;ages&quot;, remappingFunction(emp.getAge()));
		map.compute(&quot;ids&quot;, remappingFunction(emp.getId()));
	},
	(map1, map2) -&gt; {}                                          // BiConsumer combiner
);

Practically, all it does is extracting the wanted value (name, age...) and adding it to the List under the specific key &quot;names&quot;, &quot;ages&quot; 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&lt;String, List&lt;Object&gt;, List&lt;Object&gt;&gt; remappingFunction(Object object) {
	return (key, list) -&gt; {
		if (list == null)
			list = new ArrayList&lt;&gt;();
		list.add(object);
		return list;
	};
}

答案2

得分: 0

Java 8 Stream中有一些API可以将列表分割成分区,例如:

  1. Collectors.partitioningBy(..) - 基于某个Predicate创建两个分区,并返回带有值的Map&lt;Boolean, List&lt;&gt;&gt;
  2. Collectors.groupingBy() - 允许按某个键对流进行分组,并返回结果Map。

但是,这实际上不适用于您的情况,因为您想要将Emp对象的所有属性放入不同的Lists中。我不确定是否可以通过这种API实现,也许可以使用一些不太正规的方法来实现。

因此,是的,最清晰的方法是通过迭代Emp列表,并手动将所有属性输出到三个列表中,就像您提出的那样。

英文:

Java 8 Stream has some API to split the list into partition, such as:

  1. Collectros.partitioningBy(..) - which create two partitions based on some Predicate and return Map&lt;Boolean, List&lt;&gt;&gt; with values;
  2. 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.

huangapple
  • 本文由 发表于 2020年4月10日 23:28:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/61143507.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定