자바 : 포함하는 목록을 생성하는 적절한 방법이 전부가 아니다 -에 - 교차 특정 속성에 따라 주어진 두리스트의 요소?

뤼디거 :

두 개체 목록을 감안할 때, 나는 항목은 그 속성 중 하나를 기반으로 자신의 교차에없는 어떤 말할 수있을 것입니다. 다음 예제를 살펴 보자 :

나는 수업이 Foo두 가지 속성이 있습니다 booplaceholder

class Foo {
    private int boo;
    private int placeholder = 1;

    public Foo(int boo) {
        this.boo = boo;
    }

    public int getBoo() {
        return boo;
    }
}

지금은 (의이 내 입력라고하자) 그에서이 목록을 만드는 오전

    List<Foo> list1 = new ArrayList<Foo>();
    list1.add(new Foo(1));
    list1.add(new Foo(2));
    list1.add(new Foo(3));

    List<Foo> list2 = new ArrayList<Foo>();
    list2.add(new Foo(0));
    list2.add(new Foo(1));
    list2.add(new Foo(2));

그리고 지금은에있는 항목 말하고 싶으면 list1에서가 아니라 list2나에 list2하지에 list1자신의 속성에 따라 boo. 따라서 위의 예에서 내가 원하는 List<Foo> notInIntersectList하나를 포함하는 Foo(0)하나를 Foo(3).

    List<Foo> notInIntersectList = new ArrayList<Foo>();
    list1.forEach(li1foo -> {
        boolean inBothLists = false;
        list2.forEach(li2foo -> {
            if (li1foo.getBoo() == li2foo.getBoo()) {
                inBothLists = true;
            }
        });
        if (!inBothLists) {
            notInIntersectList.add(li1foo);
        }
    });
    //now I covered all items in list1 but not in list2. Now do this again with lists swapped, so I can also cover those.
    //...

슬프게도 나는 점점 오전 Local variable inBothLists defined in an enclosing scope must be final or effectively final오류로. 이것은 "오른쪽"솔루션으로하지 보이기 때문에 어떻게이 문제가 제대로 해결?

user7 :

당신은 람다 식 내부의 mutate 변수는 없습니다 (관련 항목 : 람다 식에 사용 된 변수는 최종 또는 효과적으로 최종해야한다 )

여기에 코드 (스트림 재미)를 해결하는 방법이있다

List<Foo> notInIntersectList = list1.stream()
        .filter(fooElementFromList1 -> list2
                .stream()
                .noneMatch(fooElementFromList2 -> fooElementFromList2.getBoo() == fooElementFromList1.getBoo()))
        .collect(Collectors.toCollection(ArrayList::new));

list2.stream()
        .filter(fooElementFromList2 -> list1
            .stream()
            .noneMatch(fooElementFromList1 -> fooElementFromList1.getBoo() == fooElementFromList2.getBoo()))
        .forEach(notInIntersectList::add);

이것의 복잡성이다 O(n*m)(여기서 nm는 각각리스트 1과리스트 2의 요소 수이다).

이에서 작업을 수행하려면 O(n+m), 당신은 설정을 사용할 수 있습니다. 이를 위해, 당신은 필요 equals하고 hashcode온 방법 Foo클래스입니다. 이 두 고려 Foo만 인스턴스 변수의 값에 기초하여 동일하게 인스턴스 boo.

class Foo {
    ....

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Foo other = (Foo) obj;
        return boo == other.boo;
    }

    @Override
    public int hashCode() {
        return boo;
    }
}

그리고 사용 Set이에 대한을

Set<Foo> fooSet1 = new HashSet<>(list1);
Set<Foo> fooSet2 = new HashSet<>(list2);

fooSet1.removeAll(list2);
fooSet2.removeAll(list1);

List<Foo> notInIntersectList = Stream.concat(fooSet1.stream(), fooSet2.stream())
            .collect(Collectors.toList());

추천

출처http://43.154.161.224:23101/article/api/json?id=177530&siteId=1