使用 Java8 Streams 从另外两个列表创建对象列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22933296/
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
Using Java8 Streams to create a list of objects from another two lists
提问by mat_boy
I have the following Java6 and Java8 code:
我有以下 Java6 和 Java8 代码:
List<ObjectType1> lst1 = // a list of ObjectType1 objects
List<ObjectType2> lst2 = // a list of ObjectType1 objects, same size of lst1
List<ObjectType3> lst3 = new ArrayLis<ObjectType3>(lst1.size());
for(int i=0; i < lst1.size(); i++){
lst3.add(new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()));
}
Is there any way in Java8 to handle the previous for in a more concise way using Lambda?
Java8 中有什么方法可以使用 Lambda 以更简洁的方式处理以前的 for 吗?
采纳答案by assylias
A Stream is tied to a given iterable/Collection so you can't really "iterate" two collections in parallel.
Stream 与给定的可迭代/集合相关联,因此您无法真正并行“迭代”两个集合。
One workaround would be to create a stream of indexes but then it does not necessarily improve over the for loop. The stream version could look like:
一种解决方法是创建索引流,但它不一定会改进 for 循环。流版本可能如下所示:
List<ObjectType3> lst3 = IntStream.range(0, lst1.size())
.mapToObj(i -> new ObjectType3(lst1.get(i).getAVal(), lst2.get(i).getAnotherVal()))
.collect(toList());
回答by skiwi
You could create a method that transforms two collections into a new collection, like this:
您可以创建一个将两个集合转换为一个新集合的方法,如下所示:
public <T, U, R> Collection<R> singleCollectionOf(final Collection<T> collectionA, final Collection<U> collectionB, final Supplier<Collection<R>> supplier, final BiFunction<T, U, R> mapper) {
if (Objects.requireNonNull(collectionA).size() != Objects.requireNonNull(collectionB).size()) {
throw new IllegalArgumentException();
}
Objects.requireNonNull(supplier);
Objects.requireNonNull(mapper);
Iterator<T> iteratorA = collectionA.iterator();
Iterator<U> iteratorB = collectionB.iterator();
Collection<R> returnCollection = supplier.get();
while (iteratorA.hasNext() && iteratorB.hasNext()) {
returnCollection.add(mapper.apply(iteratorA.next(), iteratorB.next()));
}
return returnCollection;
}
The important part here is that it will map the obtained iteratorA.next()
and iteratorB.next()
into a new object.
这里的重要部分是它将获取的iteratorA.next()
和映射iteratorB.next()
到一个新的对象中。
It is called like this:
它是这样调用的:
List<Integer> list1 = IntStream.range(0, 10).boxed().collect(Collectors.toList());
List<Integer> list2 = IntStream.range(0, 10).map(n -> n * n + 1).boxed().collect(Collectors.toList());
singleCollectionOf(list1, list2, ArrayList::new, Pair::new).stream().forEach(System.out::println);
In your example it would be:
在您的示例中,它将是:
List<ObjectType3> lst3 = singleCollectionOf(lst1, lst2, ArrayList::new, ObjectType3::new);
Where for example Pair::new
is a shorthand for the lamdda (t, u) -> new Pair(t, u)
.
例如 wherePair::new
是 lamdda 的简写(t, u) -> new Pair(t, u)
。
回答by Ryan Griffin
I haven't found a way to update 1 stream to another, however, I accomplished a similar feat using a Map. :)
我还没有找到将 1 个流更新到另一个流的方法,但是,我使用 Map 完成了类似的壮举。:)
Map<Integer, String> result = new HashMap<>();
for(int index = 100; index > 0; index--){
result.put(index, String.valueOf(index));
}
result.keySet().stream()
.filter(key -> key%3 == 0)
.sorted()
.forEach(key -> result.put(key, "Fizz"));
result.keySet().stream()
.filter(key -> key%5 == 0)
.sorted()
.forEach(key -> result.put(key, "Buzz"));
result.keySet().stream()
.filter(key -> key%3 == 0 && key%5 == 0)
.sorted()
.forEach(key -> result.put(key, "FizzBuzz"));
result.keySet().stream().forEach(key -> System.out.println(result.get(key)));