programing

Java 8 lamda 목록에서 요소 가져오기 및 제거

copysource 2022. 10. 21. 22:15
반응형

Java 8 lamda 목록에서 요소 가져오기 및 제거

요소 목록을 지정하면 지정된 속성을 가진 요소를 가져와 목록에서 제거합니다.제가 찾은 최고의 솔루션은 다음과 같습니다.

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 docs

조건: 제건건 assum:producersProcedureActive는 입니다.List

메모: 이 방법으로는 삭제된 아이템을 입수할 수 없습니다.

작업을 수행하려면 vanilla java 반복기를 사용하는 것이 좋습니다.

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. 나 할 수 Iterablestream()지원(적어도 반복기에 구현된 지원)

단점:

  1. 단일 식으로는 수행할 수 없습니다(보조 메서드 또는 변수 필요).

에 대해서는

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

다른 답변들은 그것이 가능하다는 것을 분명히 보여주지만, 당신은 알아두어야 한다.

  1. 검색 및 제거는 목록을 두 번 통과할 수 있습니다.
  2. ConcurrentModificationException할 때 수 .

직접 해결 방법은 에서 반환한 옵션에서 호출하는 것입니다.이 컨슈머는 옵션이 비어 있지 않을 때 호출됩니다.또, 현재의 코드와 같이, 검색 조작에 의해서 빈 옵션이 반환되어도 예외를 발생시키지 않는 것이 장점입니다.

반환하는 는, 「」로 할 수 .mapOptionalremove:

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

그러나 이 작업은 다시 목록을 통과하여 제거할 요소를 찾습니다.랜덤 액세스를 가진 리스트가 있는 경우, 예를 들어ArrayList목록 인덱스 위에 스트림을 만들어 술어와 일치하는 첫 번째 인덱스를 찾는 것이 좋습니다.

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

이 솔루션을 사용하면 작업이 인덱스에서 직접 수행됩니다.

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]발견된 요소가 유지되거나 null이 됩니다.

여기서의 「꼼수」는, 사실상 최종적인 어레이 레퍼런스를 사용하고, 그 첫 번째 요소를 설정함으로써, 「효과적인 최종」의 문제를 회피하는 것입니다.

Eclipse 컬렉션과 함께 사용할 수 있습니다.detectIndex와 함께remove(int)모든 java.displaces에서 사용할 수 있습니다.목록.

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

Eclipse 컬렉션의 유형을 사용하는 경우detectIndexmethod를 직접 리스트에 올립니다.

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 Collections의 커밋입니다.

아래 논리는 원래 목록을 수정하지 않는 해결책입니다.

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

List<String> str3 = str1.stream()
                        .filter(item -> !str2.contains(item))
                        .collect(Collectors.toList());

str1 // ["A", "B", "C", "D"]
str2 // ["D", "E"]
str3 // ["A", "B", "C"]

리스트에서 여러 요소를 새 리스트로 가져와(술어를 사용하여 필터링) 기존 리스트에서 삭제하려고 할 때 적절한 답변을 찾을 수 없었습니다.

Java Streaming API 파티셔닝을 사용하여 이를 수행할 수 있는 방법은 다음과 같습니다.

Map<Boolean, List<ProducerDTO>> classifiedElements = producersProcedureActive
    .stream()
    .collect(Collectors.partitioningBy(producer -> producer.getPod().equals(pod)));

// get two new lists 
List<ProducerDTO> matching = classifiedElements.get(true);
List<ProducerDTO> nonMatching = classifiedElements.get(false);

// OR get non-matching elements to the existing list
producersProcedureActive = classifiedElements.get(false);

이렇게 하면 필터링된 요소를 원래 목록에서 효과적으로 제거하고 새 목록에 추가할 수 있습니다.

5.2를 참조해 주세요. Collectors.partitioning By 섹션.

다른 사람들이 제안했듯이 이는 루프 및 반복 가능한 사용 사례일 수 있습니다.제 생각에는 이것이 가장 간단한 접근법입니다.목록을 일괄 수정하려면 "실제" 기능 프로그래밍으로 간주할 수 없습니다.하지만 당신은Collectors.partitioningBy()당신의 조건을 만족시키는 요소를 가진 새 목록과 그렇지 않은 요소를 가진 새 목록을 얻기 위해서.물론 이 접근방식을 사용하면 조건을 충족하는 요소가 여러 개 있는 경우 첫 번째 요소뿐만 아니라 모든 요소가 해당 목록에 포함됩니다.

resumoRemessaPorInstrucoes.removeIf(item -> 
            item.getTipoOcorrenciaRegistro() == TipoOcorrenciaRegistroRemessa.PEDIDO_PROTESTO.getNome() ||
            item.getTipoOcorrenciaRegistro() == TipoOcorrenciaRegistroRemessa.SUSTAR_PROTESTO_BAIXAR_TITULO.getNome());

제 초기 아이디어와 당신의 답변을 종합하여 저 자신의 질문에 대한 해결책으로 보이는 것에 도달했습니다.

public ProducerDTO findAndRemove(String pod) {
    ProducerDTO p = null;
    try {
        p = IntStream.range(0, producersProcedureActive.size())
             .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
             .boxed()
             .findFirst()
             .map(i -> producersProcedureActive.remove((int)i))
             .get();
        logger.debug(p);
    } catch (NoSuchElementException e) {
        logger.error("No producer found with POD [" + pod + "]");
    }
    return p;
}

다음 명령을 사용하여 개체를 제거할 수 있습니다.remove(int)(@Tunaki에서 권장하는 바와 같이) 목록을 다시 통과하지 않고 삭제된 개체를 함수 호출자에게 반환합니다.

안전한 방법을 선택하라는 당신의 답변을 읽었습니다.ifPresent대신get이 시나리오에서는 사용할 방법을 찾을 수 없습니다.

이런 종류의 해결책에 중요한 단점이 있나요?

다음 @Holger 조언 편집

이것이 내가 필요로 하는 기능이어야 한다.

public ProducerDTO findAndRemove(String pod) {
    return IntStream.range(0, producersProcedureActive.size())
            .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))      
            .boxed()                                                                
            .findFirst()
            .map(i -> producersProcedureActive.remove((int)i))
            .orElseGet(() -> {
                logger.error("No producer found with POD [" + pod + "]"); 
                return null; 
            });
}

작업은 다음과 같습니다.get "and" remove 요소를 목록에서 삭제합니다.

p.stream().collect( Collectors.collectingAndThen( Collector.of(
    ArrayDeque::new,
    (a, producer) -> {
      if( producer.getPod().equals( pod ) )
        a.addLast( producer );
    },
    (a1, a2) -> {
      return( a1 );
    },
    rslt -> rslt.pollFirst()
  ),
  (e) -> {
    if( e != null )
      p.remove( e );  // remove
    return( e );    // get
  } ) );

상기의 변형:

    import static java.util.function.Predicate.not;

    final Optional<MyItem> myItem = originalCollection.stream().filter(myPredicate(someInfo)).findFirst();
    final List<MyItem> myOtherItems = originalCollection.stream().filter(not(myPredicate(someInfo))).toList();

    private Predicate<MyItem> myPredicate(Object someInfo) {
        return myItem -> myItem.someField() == someInfo;
    }

언급URL : https://stackoverflow.com/questions/35701337/java-8-lambda-get-and-remove-element-from-list

반응형