Потоки Java 8 - фильтр, сравнивая два списка - PullRequest
1 голос
/ 27 сентября 2019

У меня есть 2 списка, которые отличаются друг от друга

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 - это 2 разных pojos с разными именами свойств, однако содержание / значение, которое содержится в имени, городе& differentName, свойство DifferentCity соответственно одинаково, т.е. test1, test2, test3 & city1, city2 и т. д.

Теперь мне нужно отфильтровать app1List, сравнивая имена и город в другом списке, т.е. app2List, который не существует.

конечный результат будет

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

Самый простой способ - это зацикливать один из других списков несколько раз, чего я пытаюсь избежать.Есть ли способ в потоках Java 7 без необходимости многократно повторять цикл?

Ответы [ 3 ]

2 голосов
/ 27 сентября 2019

Вы можете использовать операцию 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());

Предполагается, что комбинация name и city совпадает при filter ing.

0 голосов
/ 27 сентября 2019

Предполагая, что вы хотите сопоставить как имя, так и город, вы можете создать функцию, которая сопоставляет объекты с ключом , например:

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 - длины списка.

0 голосов
/ 27 сентября 2019

Вам необходимо override equals метод в App2 классе:

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

, а затем вы можете использовать Streams в вашем списке1 следующим образом:

app1List = app1List.stream()
                .filter(a-> !app2List.contains(new App2(a.getName(),a.getCity())))
                .collect(Collectors.toList());

Output:

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

...