[java] Java 8 람다 목록에서 요소 가져 오기 및 제거

요소의 목록을 감안할 때, 나는 주어진 속성 요소를 싶어 하고 목록에서 제거합니다. 내가 찾은 최고의 솔루션은 다음과 같습니다.

ProducerDTO p = producersProcedureActive
                .stream()
                .filter(producer -> producer.getPod().equals(pod))
                .findFirst()
                .get();
producersProcedureActive.remove(p);

람다 식에서 get과 remove를 결합 할 수 있습니까?



답변

목록에서 요소를 제거하려면

objectA.removeIf(x -> conditions);

예 :

objectA.removeIf(x -> blockedWorkerIds.contains(x));

List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");

List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");

str1.removeIf(x -> str2.contains(x));

str1.forEach(System.out::println);

출력 :
A B C


답변

스레드가 꽤 오래되었지만 여전히 솔루션을 제공하는 것으로 생각됩니다 Java8.

removeIf기능을 사용하십시오 . 시간 복잡성은O(n)

producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));

API 참조 : removeIf 문서

가정은 : producersProcedureActiveA는List

참고 :이 접근 방식을 사용하면 삭제 된 항목을 유지할 수 없습니다.


답변

바닐라 자바 ​​반복기를 사용하여 작업을 수행하는 것이 좋습니다.

public static <T> T findAndRemoveFirst(Iterable<? extends T> collection, Predicate<? super T> test) {
    T value = null;
    for (Iterator<? extends T> it = collection.iterator(); it.hasNext();)
        if (test.test(value = it.next())) {
            it.remove();
            return value;
        }
    return null;
}

장점 :

  1. 분명하고 분명합니다.
  2. 일치하는 요소까지 한 번만 순회합니다.
  3. 지원 Iterable없이도 할 수 있습니다 (적어도 반복기에서 구현 하는 사람들 ) .stream()remove()

단점 :

  1. 단일 표현식으로 제자리에서 수행 할 수 없습니다 (보조 방법 또는 변수 필요).

에 관해서

람다 식에서 get과 remove를 결합 할 수 있습니까?

다른 답변은 가능하다는 것을 명확하게 보여 주지만

  1. 검색 및 제거는 목록을 두 번 탐색 할 수 있습니다.
  2. ConcurrentModificationException 반복되는 목록에서 요소를 제거 할 때 throw 될 수 있습니다.


답변

직접적인 해결책은 ifPresent(consumer)에서 반환 된 Optional 을 호출 하는 것 findFirst()입니다. 이 소비자는 선택 사항이 비어 있지 않을 때 호출됩니다. 또한 현재 코드 에서처럼 find 작업이 빈 옵션을 반환하면 예외가 발생하지 않습니다. 대신 아무 일도 일어나지 않을 것입니다.

당신이 삭제 된 값을 반환 할 경우, 수 호출의 결과로 :mapOptionalremove

producersProcedureActive.stream()
                        .filter(producer -> producer.getPod().equals(pod))
                        .findFirst()
                        .map(p -> {
                            producersProcedureActive.remove(p);
                            return p;
                        });

그러나 remove(Object)작업은 제거 할 요소를 찾기 위해 목록을 다시 탐색합니다. 와 같이 임의 액세스 권한이있는 목록이있는 경우 목록 ArrayList의 인덱스에 대해 Stream을 만들고 술어와 일치하는 첫 번째 인덱스를 찾는 것이 좋습니다.

IntStream.range(0, producersProcedureActive.size())
         .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
         .boxed()
         .findFirst()
         .map(i -> producersProcedureActive.remove((int) i));

이 솔루션을 사용하면 remove(int)작업이 인덱스에서 직접 작동합니다.


답변

사용은 Java 8의 필터를 사용할 수 있으며 이전 목록을 변경하지 않으려면 다른 목록을 만들 수 있습니다.

List<ProducerDTO> result = producersProcedureActive
                            .stream()
                            .filter(producer -> producer.getPod().equals(pod))
                            .collect(Collectors.toList());


답변

나는 이것이 인기없는 대답이 될 것이라고 확신하지만 작동합니다 …

ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
            .stream()
            .filter(producer -> producer.getPod().equals(pod))
            .findFirst()
            .ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}

p[0] 발견 된 요소를 보유하거나 널이됩니다.

여기서 “트릭” 은 사실상 최종적인 배열 참조를 사용 하지만 첫 번째 요소를 설정 하여 “효과적으로 최종”문제를 우회하는 것입니다.


답변

함께 이클립스 컬렉션 당신이 사용할 수 detectIndex와 함께 remove(int)어떤 java.util.List를합니다.

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = Iterate.detectIndex(integers, i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

MutableListEclipse Collections 의 유형 을 사용하는 경우 detectIndex목록에서 직접 메소드를 호출 할 수 있습니다 .

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = integers.detectIndex(i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

참고 : 저는 Eclipse 컬렉션의 커미터입니다.