Java 8流 - 通过比较两个列表进行过滤

3

我有两个不同的列表

,它们与彼此不同。
public class App1{
    private String name;
    private String city;

    // getter setter

    // constructors
}

public class App2{
    private String differentName;
    private String differentCity;
    private String someProperty1;
    private String someProperty2;

    // getter setter

    // constructors
}

List<App1> app1List = new ArrayList<>();
app1List.add(new App1("test1","city1"));
app1List.add(new App1("test2","city2"));
app1List.add(new App1("test3","city3"));
app1List.add(new App1("test4","city4"));

List<App2> app2List = new ArrayList<>();
app2List.add(new App2("test2","city2"));
app2List.add(new App2("test3","city3"));

正如您所看到的,App1和App2类是两个不同的POJO,具有不同的属性名称,但是分别由name、city和differentName、differentCity属性持有的内容/值相同,即test1、test2、test3和city1、city2等。

现在我需要过滤app1List,比较其他列表中的名称和城市,即不存在于app2List中。

最终输出将是:

app1List.add(new App1("test1","city1"));
app1List.add(new App1("test4","city4"));

最简单的方法是循环其他列表多次,但我想避免这种情况。有没有在Java 8流中的方法,而不必多次循环?

先将一个列表转换为哈希集合。 - undefined
1
如果你有一个输入app2List.add(new App2("test1","city4""));,又会怎么样呢? - undefined
3个回答

6
您可以利用noneMatch操作,例如:
List<App1> result = app1List.stream()
        .filter(app1 -> app2List.stream()
                .noneMatch(app2 -> app2.getDifferentCity().equals(app1.getCity()) &&
                        app2.getDifferentName().equals(app1.getName())))
        .collect(Collectors.toList());

这里假设在filter过程中同时匹配namecity的组合。

0
你需要在App2类中覆盖(override)equals方法:
public class App2{
    private String differentName;
    private String differentCity;
    private String someProperty1;
    private String someProperty2;

    // getter setter

    // constructors

    @Override
    public boolean equals(Object obj) {
       App2 app2 = (App2) obj;
       return this.differentName.equals(app2.getDifferentName()) && this.differentCity.equals(app2.getDifferentCity());
    }
}

然后你可以像这样在你的list1上使用Streams:
app1List = app1List.stream()
                .filter(a-> !app2List.contains(new App2(a.getName(),a.getCity())))
                .collect(Collectors.toList());

输出:

[App1{name='测试1', city='城市1'}, App1{name='测试4', city='城市4'}]


0
假设你想要匹配姓名和城市,你可以创建一个将对象映射到键的函数,例如:
public static Integer key(String name, String differentCity) {
    return Objects.hash(name, differentCity);
}

然后使用该键创建一组键以通过noneMatch进行筛选,例如:
Set<Integer> sieve = app2List.stream()
        .map(app2 -> key(app2.differentName, app2.differentCity)).collect(Collectors.toSet());

List<App1> result = app1List.stream().filter(app1 -> sieve.stream()
        .noneMatch(i -> i.equals(key(app1.name, app1.city))))
        .collect(Collectors.toList());

System.out.println(result);

输出

[App1{name='test1', city='city1'}, App1{name='test4', city='city4'}]

这种方法的复杂度是 O(n + m),其中 n 和 m 是列表的长度。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接