Java 8如何从两个集合中过滤掉不同的实体?

时间:2015-11-11 07:09:32

标签: java java-8 guava java-stream

我想使用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我想使用stream api而不是使用foreach,你可以为我举个例子吗?谢谢

4 个答案:

答案 0 :(得分:7)

因此,如果我理解正确,您希望创建一个包含usersB所有用户的新列表,除了那些与usersA中任何用户同名的用户,对吧? / p>

首先,我会改变策略:不是添加所有用户,而是删除一些用户,我只会添加属于列表的用户。

在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());

答案 1 :(得分:3)

您应该避免使用线性搜索重复查找,就像使用嵌套循环一样。当馆藏增长时,这可能会成为一场性能灾难。

首先,将第一个集合的名称收集到支持所需查找的Set中:

Set<String> namesInA=usersA.stream().map(User::getName)
    .collect(Collectors.toCollection(() -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER)));

然后你可以用两种方式中的任何一种来执行操作:

  1. 集合中就地:

    List<User> tempUser = new ArrayList<>(usersB);
    tempUser.removeIf(u -> namesInA.contains(u.getName()));
    
  2. 使用流API将匹配元素收集到新集合中:

    List<User> tempUser = usersB.stream()
        .filter(u->!namesInA.contains(u.getName()))
        .collect(Collectors.toList());
    

答案 2 :(得分:0)

我会做那样的事情:

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());

}

答案 3 :(得分:-1)

这可以在没有java 8中的任何流的情况下完成,甚至在以前的java版本之前更好。

http://docs.oracle.com/javase/7/docs/api/java/util/Collection.html允许您删除其他集合中的一个集合的所有项目。对于来电者来说,这是一个单行,然后

equals

当集合的对象实现{{1}}

时,这是正确的