development

Java 8 Lambda를 사용하여 스트림에서 다양한 항목을 얻는 방법은 무엇입니까?

big-blog 2020. 12. 30. 20:15
반응형

Java 8 Lambda를 사용하여 스트림에서 다양한 항목을 얻는 방법은 무엇입니까?


이전 질문에서 [ Java 8에서 동적으로 필터링하는 방법은 무엇입니까? ] Stuart Marks는 훌륭한 답변을했으며 스트림에서 topN 및 topPercent를 선택하는 데 유용한 여러 유틸리티를 제공했습니다.

그의 원래 답변에서 여기에 포함시킬 것입니다.

@FunctionalInterface
public interface Criterion {
    Stream<Widget> apply(Stream<Widget> s);
}

Criterion topN(Comparator<Widget> cmp, long n) {
    return stream -> stream.sorted(cmp).limit(n);
}

Criterion topPercent(Comparator<Widget> cmp, double pct) {
    return stream -> {
        List<Widget> temp =
            stream.sorted(cmp).collect(toList());
        return temp.stream()
                   .limit((long)(temp.size() * pct));
    };
}

여기 내 질문은 다음과 같습니다.

[1] 일정량의 항목이있는 스트림에서 3에서 7까지의 상위 항목을 가져 오는 방법, 따라서 스트림에 A1, A2 .. A10의 항목이있는 경우

topNFromRange(Comparator<Widget> cmp, long from, long to) = topNFromRange(comparing(Widget::length), 3L, 7L)

{A3, A4, A5, A6, A7}을 반환합니다.

내가 생각할 수있는 가장 간단한 방법은 원본에서 상위 7 [T7]을 가져오고 원본에서 상위 3 [T3]를 가져온 다음 T7-T3를 얻는 것입니다.

[2] 일정량의 항목이있는 스트림에서 상위 10 %에서 상위 30 %로 상위 항목을 가져 오는 방법, 따라서 스트림에 X1, X2 .. X100의 항목이있는 경우

topPercentFromRange(Comparator<Widget> cmp, double from, double to) = topNFromRange(comparing(Widget::length), 0.10, 0.30)

{X10, X11, X12, ..., X29, X30}을 반환합니다.

내가 생각할 수있는 가장 간단한 방법은 원본에서 상위 30 % [TP30]를 가져오고 원본에서 상위 10 % [TP10]를 얻은 다음 TP30-TP10을 가져 오는 것입니다.

위의 상황을 간결하게 표현하기 위해 Java 8 Lambda를 사용하는 더 좋은 방법은 무엇입니까?


사용자 skiwi는 이미 질문 의 첫 번째 부분에 답변했습니다. 두 번째 부분은 다음과 같습니다.

(2) 일정량의 항목이있는 스트림에서 상위 10 %에서 상위 30 %로 상위 항목을 얻는 방법 ....

이렇게하려면 다른 질문에 대한 topPercent답변 과 유사한 기술을 사용해야합니다 . 즉, 일부 업스트림 필터링이 완료된 후 요소 수를 얻으려면 요소를 목록으로 수집해야합니다.

당신이 수를 갖게되면, 당신은에 대한 올바른 값을 계산 skip하고 limit개수하고 원하는 비율에 따라. 다음과 같이 작동 할 수 있습니다.

Criterion topPercentFromRange(Comparator<Widget> cmp, double from, double to) {
    return stream -> {
        List<Widget> temp =
            stream.sorted(cmp).collect(toList());
        return temp.stream()
                   .skip((long)(temp.size() * from))
                   .limit((long)(temp.size() * (to - from)));
    };
}

물론 from및에서 오류 검사를 수행해야합니다 to. 더 미묘한 문제는 방출 할 요소의 수를 결정하는 것입니다. 예를 들어, 10 개의 요소가있는 경우 인덱스 [0..9]에 있으며 0 %, 10 %, 20 %, ..., 90 %에 해당합니다. 그러나 9 %에서 11 % 사이의 범위를 요청하면 위의 코드는 예상 한대로 10 %의 요소가 아닌 요소를 전혀 방출하지 않습니다. 따라서 수행하려는 작업의 의미를 맞추려면 백분율 계산을 약간 수정해야 할 것입니다.


에서 범위를 가져 오려면을 Stream<T>사용 skip(long n)하여 먼저 설정된 요소 수를 건너 뛴 다음 limit(long n)특정 양의 항목 만 가져 오도록 호출 할 수 있습니다.

요소가 10 개인 스트림을 고려한 다음 요소 3에서 7을 얻으려면 일반적으로 a에서 호출합니다 List.

list.subList(3, 7);

이제를 사용하면 Stream먼저 3 개 항목을 건너 뛴 다음 7-3 = 4 개 항목을 가져와야합니다.

stream.skip(3).limit(4);

두 번째 답변에 대한 @StuartMarks의 솔루션에 대한 변형으로, 체인 가능성을 그대로 유지하는 다음 솔루션을 제공 할 것입니다. @StuartMarks가 수행하는 방식과 유사하게 작동합니다.

private <T> Collector<T, ?, Stream<T>> topPercentFromRangeCollector(Comparator<T> comparator, double from, double to) {
    return Collectors.collectingAndThen(
        Collectors.toList(),
        list -> list.stream()
            .sorted(comparator)
            .skip((long)(list.size() * from))
            .limit((long)(list.size() * (to - from)))
    );
}

IntStream.range(0, 100)
        .boxed()
        .collect(topPercentFromRangeCollector(Comparator.comparingInt(i -> i), 0.1d, 0.3d))
        .forEach(System.out::println);

그러면 10에서 29까지의 요소가 인쇄됩니다.

그것은 사용하여 작동 Collector<T, ?, Stream<T>>로 스트림로부터 요소에 소요, 변환을 List<T>한 후 획득, Stream<T>그것을 정렬하고 그것에 (올바른) 경계를 적용한다.

ReferenceURL : https://stackoverflow.com/questions/22917270/how-to-get-a-range-of-items-from-stream-using-java-8-lambda

반응형