Java 스트림 : 여러 범위의 필터


9

리소스를 필터링하고 필드를 기반으로 일부 요소를 제외하려고합니다. 제외하려면 세트 (제외 해야하는 ID가 포함되어 있음)와 목록 (제외 해야하는 여러 범위의 ID가 포함되어 있음)가 있습니다. 아래 논리를 작성했으며 두 번째 필터 논리에 만족하지 않습니다. Java 8로 더 나은 방법이 있습니까? 범위를 포함하기 위해 동일한 작업을 수행해야합니다.

Set<String> extensionsToExclude = new HashSet<>(Arrays.asList("20","25","60","900"));
List<String> rangesToExclude = new ArrayList<>(Arrays.asList("1-10","20-25","50-70","1000-1000000"));
return directoryRecords.stream()
        .filter((directoryRecord) -> !extensionsToExclude.contains(directoryRecord.getExtensionNumber()))
        .filter((directoryRecord -> {
            Boolean include = true;
            for(String s : rangesToExclude) {
                String [] rangeArray = s.split("-");
                Integer extension = Integer.parseInt(directoryRecord.getExtensionNumber());
                if(extension <= Integer.parseInt(rangeArray[0]) && extension >= Integer.parseInt(rangeArray[1])) {
                    include = false;
                }
            }
            return include;
        }))
        .collect(Collectors.toList());

감사 :)


3
값이 Boolean필요할 때 객체를 사용하지 마십시오 boolean. 여기서는 변수 include가 완전히 사용되지 않습니다. 유일하게 가능한 변화에서 인 경우 truefalse, 당신은 대체 할 수 include = false;return false;최종 결과가 이미 결정되어있다. 그런 다음 return include;끝에는를 대체 return true;하고 변수 선언을 제거 할 수 있습니다 . directoryRecord루프에서 절대로 변경되지 않기 때문에 루프 Integer extension = Integer.parseInt(directoryRecord.getExtensionNumber());이전을 이동 하고로 변경할 Integerint있습니다.
Holger

답변:


9

나는 Range다음과 같은 커스텀 클래스로 그것을 할 것이다 .

class Range {
    private long start;
    private long end;

    Range(String start, String end) {
        this.start = Long.parseLong(start);
        this.end = Long.parseLong(end);
    }

    Range(String range) {
        this(range.split("-")[0], range.split("-")[1]);
    }

    boolean inRange(long n) {
        returns start <= n && n <= end;
    }
}

다음과 같은 것이 가능해집니다.

List<Range> ranges = rangesToExclude.stream()
                     .map(Range::new).collect(Collectors.toList());
return directoryRecords.stream()
        .filter((directoryRecord) -> !extensionsToExclude
                                    .contains(directoryRecord.getExtensionNumber()))
        .filter(directoryRecord -> ranges.stream()
                                    .noneMatch(r -> r.isInRange(directoryRecord)))
        .collect(Collectors.toList());

나는 개인적으로 첫 번째 필터를 그대로 보존하기에 충분하다고 생각합니다.


2
noneMatch우리가 얘기 할 때 해서는 안되나요 rangesToExclude? 그리고 나는 더 우아한 솔루션이 될 수 있다고 생각합니다 TreeSet<Range>.
Holger

정말로, 나는 졸려 야했다.
ernest_k

@ernest_k 솔루션 주셔서 감사합니다. 정말 우아하다고 생각합니다.
Yadvendra Rathore

4

나는 ernest_k 의 대답과 비슷한 것을 제안 할 것 입니다 Range.

그러나이 방법에서는 컬렉션을 모두 사용하여 List<Range>(이를 "20"처리 할 수 ​​있음 "20-20") 및 부정을 사용하도록 필터 조건을 변경할 수 있습니다 anyMatch.

List<Range> ranges = Stream.concat(extensionsToExclude.stream(), rangesToExclude.stream())
        .map(Range::creatRange).collect(Collectors.toList());

return directoryRecords.stream()
        .filter(directoryRecord -> !ranges.stream()
                .anyMatch(r -> r.isInRange(
                        Integer.parseInt(directoryRecord.getExtensionNumber()))
                ))
        .collect(Collectors.toList());
class Range {
    private int start;
    private int end;

    Range(String start, String end) {
        this.start = Integer.parseInt(start);
        this.end = Integer.parseInt(end);
    }

    static Range creatRange(String range) {
        if (range.contains("-")) {
            return new Range(range.split("-")[0], range.split("-")[1]);
        }
        return new Range(range, range);
    }

    boolean isInRange(int n) {
        return start <= n && n <= end;
    }
}

최신 정보

에서 생성 된 범위에있는 List<Range> ranges점을 제거하도록 생성을 변경할 수 있습니다 . 그러면 불필요한 범위가 생성되지 않습니다.Set<String> extensionsToExcludeList<String> rangesToExclud

List<Range> ranges = rangesToExclude.stream().map(Range::creatRange)
        .collect(Collectors.toCollection(ArrayList::new));
extensionsToExclude.stream()
        .filter(v -> !ranges.stream()
                .anyMatch(r -> r.isInRange(Integer.parseInt(v))))
        .map(Range::creatRange)
        .forEach(ranges::add);

0

범위 조건이 참이면 모든 항목이 평가 될 때까지 기다리지 않고 조기 중단을 수행 할 수 있습니다.

if(extension >= Integer.parseInt(rangeArray[0]) && extension <= Integer.parseInt(rangeArray[1])) {
                    return true;
                }

그렇지 않으면 for 루프 후에 false를 반환합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.