为了账号安全,请及时绑定邮箱和手机立即绑定

如何根据 Predicate 过滤 Iterable?

如何根据 Predicate 过滤 Iterable?

沧海一幻觉 2022-12-21 16:37:35
我想做一个字符串列表过滤函数,使用一个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"}
查看完整描述

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

}


查看完整回答
反对 回复 2022-12-21
?
繁星淼淼

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

}


查看完整回答
反对 回复 2022-12-21
?
慕的地8271018

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;

}


查看完整回答
反对 回复 2022-12-21
?
猛跑小猪

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在实际请求下一个元素之前提前。你可能认为后者是不可取的。


查看完整回答
反对 回复 2022-12-21
  • 4 回答
  • 0 关注
  • 109 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信