스트림을 두 개로 나눌 수 있습니까?
Java 8 스트림으로 표시되는 데이터 세트가 있습니다.
Stream<T> stream = ...;
랜덤 서브셋을 취득하기 위해서 필터링 하는 방법을 확인할 수 있습니다.예를 들어,
Random r = new Random();
PrimitiveIterator.OfInt coin = r.ints(0, 2).iterator();
Stream<T> heads = stream.filter((x) -> (coin.nextInt() == 0));
또, 이 스트림을 줄여, 예를 들면, 데이터 세트의 랜덤한 2개의 반쪽을 나타내는 2개의 리스트를 취득해, 그것들을 스트림으로 되돌리는 방법도 알 수 있습니다.단, 초기 스트림에서 직접 2개의 스트림을 생성하는 방법이 있습니까?뭐랄까
(heads, tails) = stream.[some kind of split based on filter]
통찰해 주셔서 감사합니다.
이를 위해 수집기를 사용할 수 있습니다.
- 카테고리에 는, 「」를 합니다.
Collectors.partitioningBy()
★★★★★★★★★★★★★★★★★★」
하면 " " " 가 생성됩니다.Map<Boolean, List>
, , , , , , , , 을 을 하나 다른 .Predicate
.
주의: 스트림을 통째로 소비해야 하므로 무한 스트림에서는 사용할 수 없습니다.또한 스트림이 소비되기 때문에 이 메서드는 메모리 포함 스트림을 새로 만드는 대신 단순히 목록에 넣습니다.출력으로 스트림이 필요한 경우 언제든지 이러한 목록을 스트리밍할 수 있습니다.
또, 반복기는 불필요합니다.또, 제공하신 헤드 전용의 예에서도 마찬가지입니다.
- 이진 분할은 다음과 같습니다.
Random r = new Random();
Map<Boolean, List<String>> groups = stream
.collect(Collectors.partitioningBy(x -> r.nextBoolean()));
System.out.println(groups.get(false).size());
System.out.println(groups.get(true).size());
- 「」를 .
Collectors.groupingBy()
★★★★★★★★★★★★★★★★★★」
Map<Object, List<String>> groups = stream
.collect(Collectors.groupingBy(x -> r.nextInt(3)));
System.out.println(groups.get(0).size());
System.out.println(groups.get(1).size());
System.out.println(groups.get(2).size());
이 「」가 .Stream
, ""와 같은 IntStream
후, 이것은 「」입니다.collect(Collectors)
메서드를 사용할 수 없습니다.수집기 공장 없이 수동 방식으로 해야 할 거예요.을 사용하다
[2020-04-16 이후의 예 2.0]
IntStream intStream = IntStream.iterate(0, i -> i + 1).limit(100000).parallel();
IntPredicate predicate = ignored -> r.nextBoolean();
Map<Boolean, List<Integer>> groups = intStream.collect(
() -> Map.of(false, new ArrayList<>(100000),
true , new ArrayList<>(100000)),
(map, value) -> map.get(predicate.test(value)).add(value),
(map1, map2) -> {
map1.get(false).addAll(map2.get(false));
map1.get(true ).addAll(map2.get(true ));
});
이 예에서는 초기 컬렉션의 풀사이즈를 사용하여 ArrayLists를 초기화합니다(이것이 조금이라도 알려진 경우).이렇게 하면 최악의 경우에도 크기 조정 이벤트를 방지할 수 있지만, 2NT 공간(N = 초기 요소 수, T = 스레드 수)을 소비할 수 있습니다.공간을 속도와 맞바꾸려면 공간을 생략하거나 파티션에서 예상되는 최대 요소 수(균형 분할의 경우 일반적으로 N/2를 약간 초과함)와 같이 가장 잘 교육된 추측을 사용할 수 있습니다.
Java 9 메서드를 사용하여 다른 사람에게 불쾌감을 주지 않았으면 합니다.Java 8 버전의 경우 편집 내역을 확인하십시오.
우연히 이 질문을 떠올리게 되었고, 포크 스트림에는 타당성이 입증될 수 있는 몇 가지 사용 사례가 있다고 느꼈습니다.저는 아래의 코드를 컨슈머로서 쓰고 있기 때문에, 기능이나 그 외의 것에 적용할 수 있도록 하고 있습니다.
class PredicateSplitterConsumer<T> implements Consumer<T>
{
private Predicate<T> predicate;
private Consumer<T> positiveConsumer;
private Consumer<T> negativeConsumer;
public PredicateSplitterConsumer(Predicate<T> predicate, Consumer<T> positive, Consumer<T> negative)
{
this.predicate = predicate;
this.positiveConsumer = positive;
this.negativeConsumer = negative;
}
@Override
public void accept(T t)
{
if (predicate.test(t))
{
positiveConsumer.accept(t);
}
else
{
negativeConsumer.accept(t);
}
}
}
코드 실장은 다음과 같습니다.
personsArray.forEach(
new PredicateSplitterConsumer<>(
person -> person.getDateOfBirth().isPresent(),
person -> System.out.println(person.getName()),
person -> System.out.println(person.getName() + " does not have Date of birth")));
유감스럽게도 Stream의 JavaDoc에서는 당신이 요구하는 것에 대해 직접적으로 비판하고 있습니다.
스트림은 (중간 스트림 또는 터미널 스트림 동작을 호출하는)1회만 동작해야 합니다.이것에 의해, 예를 들면, 같은 송신원이 복수의 파이프라인을 공급하거나 같은 스트림의 복수의 트래버설을 실시하는 「포킹」스트림은 제외됩니다.
하려면 을 사용합니다.peek
그런 행동을 진심으로 원하시면 됩니다.이 경우 포킹필터를 사용하여 같은 원본 스트림소스에서2개의 스트림을 백업하는 대신 스트림을 복제하고 각각의 중복된 스트림을 적절히 필터링해야 합니다.
에 '아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아,아.Stream
사용 사례에 적합한 구조입니다.
두 개도 안Stream
1면 1로 하다★★★★★★★★★★★★★★★★★」다른 것을 동시에 생성하지 않고 어떻게 1개를 반복할 수 있을까요?을 사용하다
하지만 목록이나 뭐 그런 것에 덤프하고 싶다면
stream.forEach((x) -> ((x == 0) ? heads : tails).add(x));
이것은 스트림의 일반적인 메커니즘에 반하는 것입니다.Sa, Sb, Sb, Sa, Sb, Sa, Sa, Sb, Sa, Sa, Sb, Sa, Sa, Sb, Sa, Sa, Sa, Sb, Sa, Sa, Sb, S조작을 는, 「 」라고 .count()
Sa 서0 S0 sa sa sa sa 。는는는는는는는 는는 는잃 는잃 잃
에는 "Stream"이 있었습니다.tee()
스트림을 2로 복제하는 방식이라고 생각합니다.제제없없없없없없
Stream에는 peek() 메서드가 있지만 요건을 충족하기 위해 사용할 수 있습니다.
, '어느 정도', '어느 정도', '어느 정도', ' 정도'를 호출하면 을 얻을 수 예요.Collectors.groupingBy()
컬렉션을 새할 수 . 새 컬렉션을 만들고 새 컬렉션에서 스트림을 인스턴스화할 수 있습니다.
두 개 사시면 됩니다 Stream
12부터teeing
Random r = new Random();
PrimitiveIterator.OfInt coin = r.ints(0, 2).iterator();
List<Long> list = Stream.iterate(0, i -> coin.nextInt())
.limit(100).collect(teeing(
filtering(i -> i == 1, counting()),
filtering(i -> i == 0, counting()),
(heads, tails) -> {
return(List.of(heads, tails));
}));
System.err.println("heads:" + list.get(0) + " tails:" + list.get(1));
★★★★★★★★★★★★★★★★★,heads:51 tails:49
이게 내가 생각해 낼 수 있는 가장 덜 나쁜 대답이었어.
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
public class Test {
public static <T, L, R> Pair<L, R> splitStream(Stream<T> inputStream, Predicate<T> predicate,
Function<Stream<T>, L> trueStreamProcessor, Function<Stream<T>, R> falseStreamProcessor) {
Map<Boolean, List<T>> partitioned = inputStream.collect(Collectors.partitioningBy(predicate));
L trueResult = trueStreamProcessor.apply(partitioned.get(Boolean.TRUE).stream());
R falseResult = falseStreamProcessor.apply(partitioned.get(Boolean.FALSE).stream());
return new ImmutablePair<L, R>(trueResult, falseResult);
}
public static void main(String[] args) {
Stream<Integer> stream = Stream.iterate(0, n -> n + 1).limit(10);
Pair<List<Integer>, String> results = splitStream(stream,
n -> n > 5,
s -> s.filter(n -> n % 2 == 0).collect(Collectors.toList()),
s -> s.map(n -> n.toString()).collect(Collectors.joining("|")));
System.out.println(results);
}
}
이것은 정수의 흐름을 취해서 5로 나눈다.5보다 큰 경우 짝수만 필터링하여 목록에 넣습니다.나머지는 |와 결합합니다.
출력:
([6, 8],0|1|2|3|4|5)
모든 것을 중간 컬렉션으로 모아 스트림을 깨뜨리기 때문에 이상적이지 않습니다(또한 너무 많은 논쟁이 있습니다).
스트림에서 특정 요소를 필터링하여 오류로 기록하는 방법을 찾다가 우연히 이 질문을 발견했습니다.따라서 불필요한 구문을 가진 술어에 조기 종료 액션을 부가할 정도로 스트림을 분할할 필요가 없습니다.제가 생각해낸 건 다음과 같습니다.
public class MyProcess {
/* Return a Predicate that performs a bail-out action on non-matching items. */
private static <T> Predicate<T> withAltAction(Predicate<T> pred, Consumer<T> altAction) {
return x -> {
if (pred.test(x)) {
return true;
}
altAction.accept(x);
return false;
};
/* Example usage in non-trivial pipeline */
public void processItems(Stream<Item> stream) {
stream.filter(Objects::nonNull)
.peek(this::logItem)
.map(Item::getSubItems)
.filter(withAltAction(SubItem::isValid,
i -> logError(i, "Invalid")))
.peek(this::logSubItem)
.filter(withAltAction(i -> i.size() > 10,
i -> logError(i, "Too large")))
.map(SubItem::toDisplayItem)
.forEach(this::display);
}
}
Lombok을 사용하는 더 짧은 버전
import java.util.function.Consumer;
import java.util.function.Predicate;
import lombok.RequiredArgsConstructor;
/**
* Forks a Stream using a Predicate into postive and negative outcomes.
*/
@RequiredArgsConstructor
@FieldDefaults(makeFinal = true, level = AccessLevel.PROTECTED)
public class StreamForkerUtil<T> implements Consumer<T> {
Predicate<T> predicate;
Consumer<T> positiveConsumer;
Consumer<T> negativeConsumer;
@Override
public void accept(T t) {
(predicate.test(t) ? positiveConsumer : negativeConsumer).accept(t);
}
}
그럼 어떻게 해?
Supplier<Stream<Integer>> randomIntsStreamSupplier =
() -> (new Random()).ints(0, 2).boxed();
Stream<Integer> tails =
randomIntsStreamSupplier.get().filter(x->x.equals(0));
Stream<Integer> heads =
randomIntsStreamSupplier.get().filter(x->x.equals(1));
언급URL : https://stackoverflow.com/questions/19940319/can-you-split-a-stream-into-two-streams
'programing' 카테고리의 다른 글
Quasar Framework q-select가 v-모델의 개체를 ID보다 높게 설정함 (0) | 2022.07.13 |
---|---|
Java 패키지 이름에서 단어 구분 기호 표기법은 무엇입니까? (0) | 2022.07.12 |
vuejs 2를 몇 개의 html 페이지에서 사용하는 방법 (typescript 및 ASP)넷코어 (0) | 2022.07.12 |
선택 태그 내의 화살표 아이콘을 글꼴이 큰 아이콘으로 변경하려면 어떻게 해야 합니까?Vue-Cli를 사용하고 있습니다.나는 main.js에서 폰타썸을 수입했다. (0) | 2022.07.12 |
Java에서 Enum 켜기 (0) | 2022.07.12 |