如何根据 Predicate 过滤 Iterable?

我想做一个字符串列表过滤函数,使用一个Iterable<String>和一个谓词来选择要保留的字符串,其他的必须从列表中删除,但我并没有低估我是如何删除的。


static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {

    for (T s: it) {

        if (pred.test(s)==false) {

            // what to do here?

        }

    }

    return ...;

}

对于这个输入:


{"a","","b",""}

我预计


{"a","b"}


沧海一幻觉
浏览 110回答 4
4回答

肥皂起泡泡

AnIterable代表提供Iterator应要求的能力。因此,要使用过滤逻辑装饰现有的可迭代对象,您必须实现 decorating Iterator。static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {&nbsp; &nbsp; return () -> new Iterator<T>() {&nbsp; &nbsp; &nbsp; &nbsp; Iterator<T> sourceIterator = it.iterator();&nbsp; &nbsp; &nbsp; &nbsp; T current;&nbsp; &nbsp; &nbsp; &nbsp; boolean hasCurrent;&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public boolean hasNext() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while(!hasCurrent) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(!sourceIterator.hasNext()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T next = sourceIterator.next();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(pred.test(next)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; current = next;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hasCurrent = true;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; @Override&nbsp; &nbsp; &nbsp; &nbsp; public T next() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if(!hasNext()) throw new NoSuchElementException();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T next = current;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; current = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hasCurrent = false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return next;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; };}您可以通过它进行测试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) {&nbsp; &nbsp; return () -> StreamSupport.stream(it.spliterator(), false)&nbsp; &nbsp; &nbsp; &nbsp; .filter(pred).iterator();}

繁星淼淼

由于 anyCollection是Iterable,只需将符合条件的项目添加到新集合中并稍后返回:static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {&nbsp; &nbsp; Collection<T> collection = new ArrayList<>();&nbsp; &nbsp; for (T s: it) {&nbsp; &nbsp; &nbsp; &nbsp; if (!pred.test(s)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; collection.add(s);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; return collection;}几点见解:pred.test(s)==false表达式应简化为!pred.test(s)可以使用以下方法缩短方法的全部内容java流通过这种方式:static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {&nbsp; &nbsp; return StreamSupport.stream(it.spliterator(), false)&nbsp; &nbsp; &nbsp; &nbsp; .filter(pred)&nbsp; &nbsp; &nbsp; &nbsp; .collect(Collectors.toList());}

慕的地8271018

首先把你包装Iterable<T>成Stream<T>:纯Java:StreamSupport.stream(it.spliterator(),&nbsp;false)番石榴Streams.stream(it)流媒体StreamEx.of(it.iterator())然后按您的过滤Predicate<T>:... stream.filter(pred.negate()) ...最后返回Iterable<T>:作为lambda:return&nbsp;()&nbsp;->&nbsp;stream.iterator();作为method referencereturn&nbsp;stream::iterator;完整示例:static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {&nbsp; &nbsp; return StreamSupport.stream(it.spliterator(), false).filter(pred.negate())::iterator;}要么:static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) {&nbsp; &nbsp; Stream<T> stream = stream(it.spliterator(), false);&nbsp; &nbsp; Predicate<T> negatedPred = pred.negate();&nbsp; &nbsp; Stream<T> filteredStream = stream.filter(negatedPred);&nbsp; &nbsp; return filteredStream::iterator;}

猛跑小猪

我在评论中提到的 Holger 的替代解决方案如下所示:static <T> Iterable<T> select(Iterable<T> toIterate, Predicate<T> pred) {&nbsp; &nbsp; return () -> new Iterator<T>() {&nbsp; &nbsp; &nbsp; &nbsp; Iterator<T> delegate = toIterate.iterator();&nbsp; &nbsp; &nbsp; &nbsp; T next = findNextValid();&nbsp; &nbsp; &nbsp; &nbsp; public boolean hasNext() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return next != null;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public T next() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (next == null) throw new NoSuchElementException();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T result = next;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; next = findNextValid();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; private T findNextValid() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T result = null;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; while (result == null && delegate.hasNext()) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; T candidate = delegate.next();&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (pred.test(candidate)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result = candidate;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; };}不同之处在于,不需要额外的标记hasCurrent,它会Iterator在实际请求下一个元素之前提前。你可能认为后者是不可取的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java