Java 更好的lambda在对象层次结构上获得不同的值
我们的对象A类型包含对象B类型的数组,而不是包含对象C类型的数组,如示例中所示:Java 更好的lambda在对象层次结构上获得不同的值,java,lambda,Java,Lambda,我们的对象A类型包含对象B类型的数组,而不是包含对象C类型的数组,如示例中所示: /* sample structure that ends with 4 instances of C with ids.100,200,100,200 */ private class A{ int id; A(int id) { this.id = id; } B[] b = new B[]{new B(10), new B
/* sample structure that ends with 4 instances of C with ids.100,200,100,200 */
private class A{
int id;
A(int id) {
this.id = id;
}
B[] b = new B[]{new B(10), new B(20) };
}
private class B{
int id;
B(int id) {
this.id = id;
}
C[] c = new C[]{new C(100), new C(200) };
}
private class C{
int id;
C(int id) {
this.id = id;
}
public String toString(){
return ""+id;
}
}
如果我们试图获得所有不同的c.id(100200),第一种方法可能是
HashSet<Integer> distinctIdsOfC = new HashSet<Integer>();
for (B bbb: a.b){
for (C ccc: bbb.c){
distinctIdsOfC.add(ccc.id);
}
}
HashSet-differenticsofc=new-HashSet();
(B bbb:a.B){
适用于(ccc:bbb.C){
区别OFC.add(ccc.id);
}
}
(结果是预期的100200)
我的第一次尝试是和lambdas
List<C> a6 = Arrays.asList(a.b).stream().map(jaja -> Arrays.asList(jaja.c)).flatMap(List::stream).collect(Collectors.toList());
a6.stream().map(x->x.id).distinct().forEach(System.out::println);
lista6=Arrays.asList(a.b.stream().map(jajaja->Arrays.asList(jajaja.c)).flatMap(List::stream).collect(collector.toList());
a6.stream().map(x->x.id).distinct().forEach(System.out::println);
(结果还是预期的100200)
最后是问题有更好的兰姆达替代品吗?
/*要测试的完整源示例*/
包装试验;
导入java.util.array;
导入java.util.HashSet;
导入java.util.List;
导入java.util.stream.collector;
公开课考试{
公共静态void main(字符串[]args){
测试t=新测试();
t、 haz();
}
私有无效haz(){
A=新的A(1);
HashSet-differentidsofc=新的HashSet();
(B bbb:a.B){
适用于(ccc:bbb.C){
区别OFC.add(ccc.id);
}
}
System.out.println(“with for loop”+distributedsofc.toString());
System.out.println(“带lambda”);
lista6=Arrays.asList(a.b.stream().map(jaja->Arrays.asList(jajaja.c)).flatMap(List::stream)
.collect(Collectors.toList());
a6.stream().map(x->x.id).distinct().forEach(System.out::println);
}
私人甲级{
int-id;
A(整数id){
this.id=id;
}
B[]B=新的B[]{新的B(10),新的B(20)};
}
私人乙级{
int-id;
B(内部id){
this.id=id;
}
C[]C=newc[]{newc(100),newc(200)};
}
私人C类{
int-id;
C(内部id){
this.id=id;
}
公共字符串toString(){
返回“”+id;
}
}
}
好的,我想我们有很多选择,但是:
1) 在C类中实现Equals/hashCode,然后:
Arrays.stream(a.b)
.map(s -> s.c)
.flatMap(Arrays::stream)
.distinct()
.forEach(System.out::println)
但是,如果不能添加hashCode/equals:
2) 创建筛选器方法(按类字段区分):
有了评论中所有有价值的信息,我们寻找的是不同的id值,而不是不同的对象,并试图让它更简单, 以lambda结束
/* proposed lambda */
System.out.println("with lambda");
Set<Integer> a7 = Arrays.stream(a.b).flatMap(jaja-> Arrays.stream(jaja.c).map(jeje->jeje.id)).collect(Collectors.toSet());
System.out.println("with lambda set a7");
a7.stream().forEach(System.out::println);
/*提议的lambda*/
System.out.println(“带lambda”);
Set a7=Arrays.stream(a.b).flatMap(jaja->Arrays.stream(jajaja.c.map(jeje->jejeje.id)).collect(Collectors.toSet());
System.out.println(“带有lambda集合a7”);
a7.stream().forEach(System.out::println);
这样就避免了中间的非使用列表,避免了使用distinct,而且它更短、更清晰。
collect(Collectors.toSet())
。为什么要查看列表?不确定为什么要将流表达式分成两条语句。为什么不在flatMap
之后继续,并收集到一个集合或在结果上使用distinct?我使用了两个语句,因为这是我的第一个“真实”lambda,不包括教程、书籍或研究。没有真正的原因,只要我们处理数组,就应该使用arrays.stream
或stream.of
而不是arrays.asList().stream()
。除了map(asList)
之外,您还可以直接调用flatMap
:flatMap(jajaja->Arrays.stream(jajaja.c))
。这样你就不会创建一个你根本不需要的列表了。对,下一个更好的解决方案是Arrays.asList(a.b).stream().map(s->s.c).map(Arrays::stream).distinct()/…code…/
谢谢@roland小心map(Arrays::stream)
。。。应该是:Arrays.stream(a.b).map(s->s.c).flatMap(Arrays::stream).distinct().forEach(System.out::println)代码>好的,所以请这样内联:数组.stream(a.b).map(s->s.c).flatMap(Arrays::stream).map(s->s.id).distinct().forEach(System.out::println)
。我的答案和您的解决方案之间的区别是只添加一个.map(函数),然后您就有了简单的代码,并且您有与所有对象C类不同的ID。当您只想执行forEach(…)
时,无需使用stream()
。您只需执行a7.forEach(System.out::println)
但正如Mateusz所说,您可以在前面的流操作中执行forEach
,而不必收集到集合中。
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
Arrays.asList(a.b).stream()
.map(jaja -> Arrays.asList(jaja.c))
.flatMap(List::stream)
.filter(distinctByKey(s -> s.id))
.forEach(System.out::println);
/* proposed lambda */
System.out.println("with lambda");
Set<Integer> a7 = Arrays.stream(a.b).flatMap(jaja-> Arrays.stream(jaja.c).map(jeje->jeje.id)).collect(Collectors.toSet());
System.out.println("with lambda set a7");
a7.stream().forEach(System.out::println);