Java 8 如何从两个集合中过滤出不同的实体?
Java 8 How to filter not different entity from two collections?
我想使用 Java 8 个流过滤器集合,但我发现所有示例都是一个集合,Java 6 是:
public class User {
public Long id;
public String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
List<User> usersA = new ArrayList<>();
usersA.add(new User(1l,"A"));
usersA.add(new User(2l,"B"));
usersA.add(new User(3l,"C"));
List<User> usersB = new ArrayList<>();
usersB.add(new User(33l,"A"));
usersB.add(new User(34l,"B"));
usersB.add(new User(35l,"D"));
usersB.add(new User(36l,"C"));
List<User> tempUser = new ArrayList<>();
tempUser.addAll(usersB);
for (User user : usersA) {
for (User user1 : tempUser) {
System.out.println(user1.getName().equalsIgnoreCase(user.getName()));
if (user1.getName().equalsIgnoreCase(user.getName())){
System.out.println("remove:"+user1.getName());
tempUser.remove(user1);
break;
}
}
}
System.out.println("last:"+tempUser);
和 Java 8 我想使用流 api 而不是使用 foreach,你能给我举个例子吗?谢谢
所以,如果我理解正确的话,你想创建一个包含 usersB
的所有用户的新列表,除了那些与 usersA
中的任何用户同名的用户,对吧?
首先,我会改变策略:不是添加所有用户,然后删除一些用户,而是只添加首先属于列表的用户。
而在 Java 8 中,可以用
完成
List<User> result =
usersB.stream()
.filter(u -> !userNameIn(u, usersA))
.collect(Collectors.toList());
userNameIn
定义为
private boolean userNameIn(User u, List<User> users) {
return users.stream().anyMatch(user -> user.getName().equalsIgnoreCase(u.getName()));
}
如果 usersA
包含大量用户,那将不会很有效。一个更有效的解决方案是将 usersA
的所有小写名称存储在一个 HashSet 中,并将方法替换为
List<User> result =
usersB.stream()
.filter(u -> !lowercaseNames.contains(u.getName().toLowerCase()))
.collect(Collectors.toList());
这可以在 java 8 中没有任何流的情况下完成,在以前的 java 版本中甚至更好。
http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html 允许您删除一个集合中另一个集合中的所有项目。对于来电者来说,这是一个单行然后
userB.removeAll(userA)
当集合的对象实现equals
时,这是正确的
您应该避免像使用嵌套循环那样使用线性搜索进行重复查找。当集合增长时,这可能会成为性能灾难。
首先,将第一个集合的名称收集到支持所需查找的 Set
中:
Set<String> namesInA=usersA.stream().map(User::getName)
.collect(Collectors.toCollection(() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)));
那么您可以通过两种方式之一执行操作:
集合中的就地:
List<User> tempUser = new ArrayList<>(usersB);
tempUser.removeIf(u -> namesInA.contains(u.getName()));
使用流 API 将匹配元素收集到新集合中:
List<User> tempUser = usersB.stream()
.filter(u->!namesInA.contains(u.getName()))
.collect(Collectors.toList());
我会这样做:
public static class User {
public Long id;
public String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
}
public static void main(String[] args){
List<User> usersA = new ArrayList<>();
usersA.add(new User(1l,"A"));
usersA.add(new User(2l,"B"));
usersA.add(new User(3l,"C"));
List<User> usersB = new ArrayList<>();
usersB.add(new User(33l,"A"));
usersB.add(new User(34l,"B"));
usersB.add(new User(35l,"D"));
usersB.add(new User(36l,"C"));
List<User> list = usersB.stream()
.filter(userb -> !usersA.stream().
filter(usera -> usera.name.equalsIgnoreCase(userb.name)).findFirst().isPresent())
.collect(Collectors.toList());
}
我想使用 Java 8 个流过滤器集合,但我发现所有示例都是一个集合,Java 6 是:
public class User {
public Long id;
public String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
List<User> usersA = new ArrayList<>();
usersA.add(new User(1l,"A"));
usersA.add(new User(2l,"B"));
usersA.add(new User(3l,"C"));
List<User> usersB = new ArrayList<>();
usersB.add(new User(33l,"A"));
usersB.add(new User(34l,"B"));
usersB.add(new User(35l,"D"));
usersB.add(new User(36l,"C"));
List<User> tempUser = new ArrayList<>();
tempUser.addAll(usersB);
for (User user : usersA) {
for (User user1 : tempUser) {
System.out.println(user1.getName().equalsIgnoreCase(user.getName()));
if (user1.getName().equalsIgnoreCase(user.getName())){
System.out.println("remove:"+user1.getName());
tempUser.remove(user1);
break;
}
}
}
System.out.println("last:"+tempUser);
和 Java 8 我想使用流 api 而不是使用 foreach,你能给我举个例子吗?谢谢
所以,如果我理解正确的话,你想创建一个包含 usersB
的所有用户的新列表,除了那些与 usersA
中的任何用户同名的用户,对吧?
首先,我会改变策略:不是添加所有用户,然后删除一些用户,而是只添加首先属于列表的用户。
而在 Java 8 中,可以用
完成List<User> result =
usersB.stream()
.filter(u -> !userNameIn(u, usersA))
.collect(Collectors.toList());
userNameIn
定义为
private boolean userNameIn(User u, List<User> users) {
return users.stream().anyMatch(user -> user.getName().equalsIgnoreCase(u.getName()));
}
如果 usersA
包含大量用户,那将不会很有效。一个更有效的解决方案是将 usersA
的所有小写名称存储在一个 HashSet 中,并将方法替换为
List<User> result =
usersB.stream()
.filter(u -> !lowercaseNames.contains(u.getName().toLowerCase()))
.collect(Collectors.toList());
这可以在 java 8 中没有任何流的情况下完成,在以前的 java 版本中甚至更好。
http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html 允许您删除一个集合中另一个集合中的所有项目。对于来电者来说,这是一个单行然后
userB.removeAll(userA)
当集合的对象实现equals
您应该避免像使用嵌套循环那样使用线性搜索进行重复查找。当集合增长时,这可能会成为性能灾难。
首先,将第一个集合的名称收集到支持所需查找的 Set
中:
Set<String> namesInA=usersA.stream().map(User::getName)
.collect(Collectors.toCollection(() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)));
那么您可以通过两种方式之一执行操作:
集合中的就地:
List<User> tempUser = new ArrayList<>(usersB); tempUser.removeIf(u -> namesInA.contains(u.getName()));
使用流 API 将匹配元素收集到新集合中:
List<User> tempUser = usersB.stream() .filter(u->!namesInA.contains(u.getName())) .collect(Collectors.toList());
我会这样做:
public static class User {
public Long id;
public String name;
public User(Long id, String name) {
this.id = id;
this.name = name;
}
}
public static void main(String[] args){
List<User> usersA = new ArrayList<>();
usersA.add(new User(1l,"A"));
usersA.add(new User(2l,"B"));
usersA.add(new User(3l,"C"));
List<User> usersB = new ArrayList<>();
usersB.add(new User(33l,"A"));
usersB.add(new User(34l,"B"));
usersB.add(new User(35l,"D"));
usersB.add(new User(36l,"C"));
List<User> list = usersB.stream()
.filter(userb -> !usersA.stream().
filter(usera -> usera.name.equalsIgnoreCase(userb.name)).findFirst().isPresent())
.collect(Collectors.toList());
}