4 回答
TA贡献1829条经验 获得超6个赞
AnIterable代表提供Iterator应要求的能力。因此,要使用过滤逻辑装饰现有的可迭代对象,您必须实现 decorating Iterator。
static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
return () -> new Iterator<T>() {
Iterator<T> sourceIterator = it.iterator();
T current;
boolean hasCurrent;
@Override
public boolean hasNext() {
while(!hasCurrent) {
if(!sourceIterator.hasNext()) {
return false;
}
T next = sourceIterator.next();
if(pred.test(next)) {
current = next;
hasCurrent = true;
}
}
return true;
}
@Override
public T next() {
if(!hasNext()) throw new NoSuchElementException();
T next = current;
current = null;
hasCurrent = false;
return next;
}
};
}
您可以通过它进行测试
List<String> original = new ArrayList<>();
Collections.addAll(original, "foo", "bar", "baz");
Iterable<String> filter = select(original, s -> s.startsWith("b"));
System.out.println(String.join(", ", filter));
original.removeIf(s -> !s.endsWith("r"));
System.out.println(String.join(", ", filter));
实现这样的 , 时最大的挑战Iterator是提供两种方法hasNext和next正确的语义,而不保证调用者将如何调用它们,即你不能假设它永远不会调用hasNext()两次,也next()不会总是被调用之前hasNext()。
使用 Stream API 可以更轻松地实现相同的逻辑:
static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
return () -> StreamSupport.stream(it.spliterator(), false)
.filter(pred).iterator();
}
TA贡献1775条经验 获得超11个赞
由于 anyCollection是Iterable,只需将符合条件的项目添加到新集合中并稍后返回:
static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
Collection<T> collection = new ArrayList<>();
for (T s: it) {
if (!pred.test(s)) {
collection.add(s);
}
}
return collection;
}
几点见解:
pred.test(s)==false表达式应简化为!pred.test(s)
可以使用以下方法缩短方法的全部内容java流通过这种方式:
static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
return StreamSupport.stream(it.spliterator(), false)
.filter(pred)
.collect(Collectors.toList());
}
TA贡献1796条经验 获得超4个赞
首先把你包装Iterable<T>
成Stream<T>
:
纯Java:
StreamSupport.stream(it.spliterator(), false)
Streams.stream(it)
StreamEx.of(it.iterator())
然后按您的过滤Predicate<T>
:
... stream.filter(pred.negate()) ...
最后返回Iterable<T>
:
作为
lambda
:return () -> stream.iterator();
作为
method reference
return stream::iterator;
完整示例:
static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
return StreamSupport.stream(it.spliterator(), false).filter(pred.negate())::iterator;
}
要么:
static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {
Stream<T> stream = stream(it.spliterator(), false);
Predicate<T> negatedPred = pred.negate();
Stream<T> filteredStream = stream.filter(negatedPred);
return filteredStream::iterator;
}
TA贡献1858条经验 获得超8个赞
我在评论中提到的 Holger 的替代解决方案如下所示:
static <T> Iterable<T> select(Iterable<T> toIterate, Predicate<T> pred) {
return () -> new Iterator<T>() {
Iterator<T> delegate = toIterate.iterator();
T next = findNextValid();
public boolean hasNext() {
return next != null;
}
public T next() {
if (next == null) throw new NoSuchElementException();
T result = next;
next = findNextValid();
return result;
}
private T findNextValid() {
T result = null;
while (result == null && delegate.hasNext()) {
T candidate = delegate.next();
if (pred.test(candidate)) {
result = candidate;
}
}
return result;
}
};
}
不同之处在于,不需要额外的标记hasCurrent,它会Iterator在实际请求下一个元素之前提前。你可能认为后者是不可取的。
添加回答
举报