Java Stream: Filter with multiple ranges
I would do it with a custom Range
class, something like:
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;
}
}
Which will make something like this possible:
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());
I personally find your first filter good enough to be preserved as is.
I would suggest similar to ernest_k's answer with Range
.
But in this approach you can use both collection to create List<Range>
(this "20"
can be treated as "20-20"
) and change the filter condition to use negation with 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;
}
}
UPDATE
Creation of List<Range> ranges
can be change to remove points from Set<String> extensionsToExclude
that are in the range created from List<String> rangesToExclud
. Then unnecessary ranges will not be created.
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);