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;
}
장점:
- 그것은 명백하고 명백하다.
- 일치하는 요소까지 한 번만 통과합니다.
- 나 할 수
Iterable
stream()
지원(적어도 반복기에 구현된 지원)
단점:
- 단일 식으로는 수행할 수 없습니다(보조 메서드 또는 변수 필요).
에 대해서는
람다 식에서 get과 remove를 조합할 수 있습니까?
다른 답변들은 그것이 가능하다는 것을 분명히 보여주지만, 당신은 알아두어야 한다.
- 검색 및 제거는 목록을 두 번 통과할 수 있습니다.
ConcurrentModificationException
할 때 수 .
직접 해결 방법은 에서 반환한 옵션에서 호출하는 것입니다.이 컨슈머는 옵션이 비어 있지 않을 때 호출됩니다.또, 현재의 코드와 같이, 검색 조작에 의해서 빈 옵션이 반환되어도 예외를 발생시키지 않는 것이 장점입니다.
반환하는 는, 「」로 할 수 .map
Optional
한 remove
:
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 컬렉션의 유형을 사용하는 경우detectIndex
method를 직접 리스트에 올립니다.
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
'programing' 카테고리의 다른 글
오브젝트 범위와Object.assign(Object.assign) (0) | 2022.10.21 |
---|---|
1개의 INSERT에 여러 행의 ID를 삽입하려면 어떻게 해야 합니까? (0) | 2022.10.21 |
parseInt()와 Number()의 차이점은 무엇입니까? (0) | 2022.10.21 |
"읽기 전용" 속성을 추가하는 방법"읽기 전용" 속성을 추가하는 방법?? (0) | 2022.10.21 |
ELB를 통한 mariadb galera 클러스터를 사용하는 grails 애플리케이션에서 Mysql 연결 시간 초과 (0) | 2022.10.21 |