Luồng Java: Bộ lọc với nhiều phạm vi


9

Tôi đang cố gắng lọc tài nguyên và loại trừ một số thành phần dựa trên một trường. Để loại trừ tôi có một bộ (có chứa id cần loại trừ) và một danh sách (nó chứa nhiều phạm vi id cần loại trừ). Tôi đã viết logic dưới đây và tôi không hài lòng với logic bộ lọc thứ 2. Có cách nào tốt hơn chúng ta có thể làm với Java 8 không? Tôi cần phải làm tương tự để bao gồm cả phạm vi.

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

Cảm ơn :)


3
Đừng sử dụng Booleancác đối tượng khi bạn chỉ cần một booleangiá trị. Mặc dù ở đây, biến includelà hoàn toàn lỗi thời. Khi thay đổi duy nhất có thể là từ trueđến false, bạn có thể thay thế include = false;bằng return false;kết quả cuối cùng đã được xác định. Sau đó, return include;ở cuối có thể được thay thế return true;và khai báo biến bị loại bỏ. Và vì directoryRecordkhông bao giờ thay đổi trong vòng lặp, bạn có thể di chuyển Integer extension = Integer.parseInt(directoryRecord.getExtensionNumber());trước vòng lặp (và thay đổi Integerthành int).
Holger

Câu trả lời:


9

Tôi sẽ làm điều đó với một Rangelớp tùy chỉnh , đại loại như:

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

Điều này sẽ làm cho một cái gì đó như thế này có thể:

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

Cá nhân tôi thấy bộ lọc đầu tiên của bạn đủ tốt để được bảo tồn như hiện tại.


2
Không phải là noneMatchkhi chúng ta nói về rangesToExclude? Và tôi cho rằng, có thể có một giải pháp thậm chí thanh lịch hơn với một TreeSet<Range>...
Holger

Nó thực sự nên, tôi đã phải buồn ngủ.
ernest_k

@ernest_k Cảm ơn bạn đã giải quyết. Tôi thấy nó thực sự thanh lịch.
Yadvendra Rathore

4

Tôi sẽ đề nghị tương tự như câu trả lời của ernest_k với Range.

Nhưng trong phương pháp này, bạn có thể sử dụng cả bộ sưu tập để tạo List<Range>(điều này "20"có thể được coi là "20-20") và thay đổi điều kiện bộ lọc để sử dụng phủ định với 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;
    }
}

CẬP NHẬT

Việc tạo List<Range> rangescó thể được thay đổi để loại bỏ các điểm Set<String> extensionsToExcludetrong phạm vi được tạo từ đó List<String> rangesToExclud. Sau đó, phạm vi không cần thiết sẽ không được tạo ra.

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

bạn có thể nghỉ sớm nếu điều kiện phạm vi là đúng, thay vì chờ tất cả các mục được đánh giá.

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

mặt khác chỉ trả về false sau vòng lặp for.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.