Java 8 Streams-基于其他列表从嵌套列表中删除项
如何从集合中每个对象的列表属性中删除元素并返回相同的集合Java 8 Streams-基于其他列表从嵌套列表中删除项,java,java-8,java-stream,Java,Java 8,Java Stream,如何从集合中每个对象的列表属性中删除元素并返回相同的集合 class Student { String name; List<String> friends; // TODO constructor, getters and setters } Student chris = new Student("chris", new ArrayList<>(Arrays.asList("sean", "mike", "mary", "
class Student {
String name;
List<String> friends;
// TODO constructor, getters and setters
}
Student chris = new Student("chris",
new ArrayList<>(Arrays.asList("sean", "mike", "mary", "mark")));
Student tim = new Student("tim",
new ArrayList<>(Arrays.asList("mike", "john", "steve", "mary")));
List<Student> students = new ArrayList<>(Arrays.asList(chris, tim));
List<String> badKids = new ArrayList("mike", "sean");
我在初级阶段就在集合中使用了流,但嵌套让我感到困惑:
List<Student> studentsWithGoodFriends = students.stream()
.map(student -> student.getFriends().flatMap(student -> student.stream())
.filter(friend-> !badKids.contains(friend))
.map(Student student -> new Student...
那我就迷路了。我熟悉返回按对象属性过滤的列表,但不过滤列表属性 您需要调整代码,至少先编译。像class之类的东西,如果大写C,即使逻辑正常,也会使代码崩溃。我尽量不做太多的改变,只是为了让它发挥作用,这样你就可以看到你哪里弄错了 我还提供了几个使用不同技术的示例,以便您可以根据需要查看涉及流的选项,还包括函数引用和更传统的引用。我希望有帮助
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
class Student {
String name;
List< String > friends;
public Student( String name, List< String > friends ) {
this.name = name;
this.friends = friends;
}
public void removeFriendsIf( Predicate< String > test ) { // for example 5
getFriends( ).removeIf( test );
}
public List< String > getFriends( ) { // for example 4 -> students.forEach( e -> e.getFriends().removeIf( badKids::contains ) );
return friends;
}
public void removeFriends( List< String > badFriends ) { // no need for example here
getFriends( ).removeAll( badFriends );
}
}
class Initech {
public static void main( String[] reports ) {
Student chris = new Student( "chris", Arrays.asList( "sean", "mike", "mary", "mark" ) );
Student tim = new Student( "tim", Arrays.asList( "mike", "john", "steve", "mary" ) );
Student other = new Student( "tim", Arrays.asList( "john", "steve", "mary" ) );
List< Student > students = new ArrayList<>( );
students.add( chris );
students.add( tim );
students.add( other );
List< String > badKids = Arrays.asList( "mike", "sean" );
// Example 1 ----
// All students that do not have any of the bad friends
List< Student > studentsWithOnlyGoodFriends = students.stream( )
.filter( e -> e.friends.stream( )
.noneMatch( badKids::contains ) )
.collect( Collectors.toList( ) );
studentsWithOnlyGoodFriends.stream( )
.map( e -> e.friends )
.forEach( System.out::println );
System.out.println( );
// Example 2 ----
// All students but removing the bad apples
List< Student > studentsLostBadFriends = students.stream( )
.peek( e -> e.friends = e.friends.stream( )
.filter( f -> !badKids.contains( f ) )
.collect( Collectors.toList( ) ) )
.collect( Collectors.toList( ) );
studentsLostBadFriends.stream( )
.map( e -> e.friends )
.forEach( System.out::println );
System.out.println( );
//Example 3 ----
// The same as 2, without streams and with ArrayLists
chris = new Student( "chris", new ArrayList<>( Arrays.asList( "sean", "mike", "mary", "mark" ) ) );
tim = new Student( "tim", new ArrayList<>( Arrays.asList( "mike", "john", "steve", "mary" ) ) );
other = new Student( "tim", new ArrayList<>( Arrays.asList( "john", "steve", "mary" ) ) );
students.add( chris );
students.add( tim );
students.add( other );
students.forEach( e -> e.friends.removeIf( badKids::contains ) );
students.stream( )
.map( e -> e.friends )
.forEach( System.out::println );
//Example 4 ----
// The same as 3, without streams and with ArrayLists and the getter methods
chris = new Student( "chris", new ArrayList<>( Arrays.asList( "sean", "mike", "mary", "mark" ) ) );
tim = new Student( "tim", new ArrayList<>( Arrays.asList( "mike", "john", "steve", "mary" ) ) );
other = new Student( "tim", new ArrayList<>( Arrays.asList( "john", "steve", "mary" ) ) );
students.add( chris );
students.add( tim );
students.add( other );
students.forEach( e -> e.getFriends( )
.removeIf( badKids::contains ) );
students.stream( )
.map( e -> e.friends )
.forEach( System.out::println );
//Example 5 ----
// The same as 4, without streams and with ArrayLists and the getter methods
chris = new Student( "chris", new ArrayList<>( Arrays.asList( "sean", "mike", "mary", "mark" ) ) );
tim = new Student( "tim", new ArrayList<>( Arrays.asList( "mike", "john", "steve", "mary" ) ) );
other = new Student( "tim", new ArrayList<>( Arrays.asList( "john", "steve", "mary" ) ) );
students.add( chris );
students.add( tim );
students.add( other );
students.forEach( e -> e.removeFriendsIf( badKids::contains ) );
students.stream( )
.map( e -> e.friends )
.forEach( System.out::println );
}
}
您不需要流来完成此任务,特别是如果您想改变现有的好友列表:
students.forEach(s -> s.getFriends().removeAll(badKids));
就这样。这就使用了这个方法
要点:要使其工作,Student.getFriends方法返回的好友列表必须是可变的,例如ArrayList
尽管上面的解决方案很简洁,但它打破了封装,因为我们正在修改学生班级之外每个学生的朋友列表。要解决此问题,您需要向Student类添加一个方法:
例如,您可以通过以下方式执行此操作:
package demo;
import java.util.List;
import java.util.function.Predicate;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.*;
public class Example {
public static void main(String[] args) {
List<Student> students = asList(getChris(), getTim());
List<String> badFriends = asList("mike", "sean");
List<Student> cleanedStudentList = students.stream()
.map(student -> cleanBadFriendOnStudent(student, badFriends))
.collect(toList());
cleanedStudentList.forEach(System.out::println);
}
private static Student cleanBadFriendOnStudent(Student student, List<String> badKids) {
List<String> cleanedFriendList = student.friends.stream()
.filter(not(badKids::contains))
.collect(toList());
return new Student(student.name, cleanedFriendList);
}
private static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
private static Student getTim() {
return new Student("tim", asList("mike", "john", "steve", "mary"));
}
private static Student getChris() {
return new Student("chris", asList("sean", "mike", "mary", "mark"));
}
private static class Student {
private final String name;
private final List<String> friends;
Student(String name, List<String> friends) {
this.name = name;
this.friends = friends;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", friends=" + friends +
'}';
}
}
}
您可以这样做:
List<Students> good = st.stream()
.peek(s -> s.getFriends().removeAll(bad))
.collect(Collectors.toList());
但使用peek这种方式应该用来记录是一种反模式,您可以使用map代替
List<Students> good = st.stream()
.map(s -> {
s.getFriends().removeAll(bad);
return s;
})
.collect(Collectors.toList());
到目前为止您尝试了什么?请注意Arrays.asList创建了一个不可变的列表。如果您创建一个常规的ArrayList,则只需执行list.removeAllotherList;。这里不需要流,但需要正确的语法。目前代码很糟糕。Arrays.asList与当前问题无关,请将代码更改为使用ArrayList。谢谢!我一直在努力解决Arrays.asList的不变性问题,没有想到这个不使用字符串的函数示例。
package demo;
import java.util.List;
import java.util.function.Predicate;
import static java.util.Arrays.asList;
import static java.util.stream.Collectors.*;
public class Example {
public static void main(String[] args) {
List<Student> students = asList(getChris(), getTim());
List<String> badFriends = asList("mike", "sean");
List<Student> cleanedStudentList = students.stream()
.map(student -> cleanBadFriendOnStudent(student, badFriends))
.collect(toList());
cleanedStudentList.forEach(System.out::println);
}
private static Student cleanBadFriendOnStudent(Student student, List<String> badKids) {
List<String> cleanedFriendList = student.friends.stream()
.filter(not(badKids::contains))
.collect(toList());
return new Student(student.name, cleanedFriendList);
}
private static <T> Predicate<T> not(Predicate<T> predicate) {
return predicate.negate();
}
private static Student getTim() {
return new Student("tim", asList("mike", "john", "steve", "mary"));
}
private static Student getChris() {
return new Student("chris", asList("sean", "mike", "mary", "mark"));
}
private static class Student {
private final String name;
private final List<String> friends;
Student(String name, List<String> friends) {
this.name = name;
this.friends = friends;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", friends=" + friends +
'}';
}
}
}
Student{name='chris', friends=[mary, mark]}
Student{name='tim', friends=[john, steve, mary]}
List<Students> good = st.stream()
.peek(s -> s.getFriends().removeAll(bad))
.collect(Collectors.toList());
List<Students> good = st.stream()
.map(s -> {
s.getFriends().removeAll(bad);
return s;
})
.collect(Collectors.toList());