Java 如何根据谓词筛选Iterable?
我想使用一个Java 如何根据谓词筛选Iterable?,java,java-8,predicate,iterable,java-stream,Java,Java 8,Predicate,Iterable,Java Stream,我想使用一个Iterable和一个谓词来执行一个字符串列表过滤函数,以选择要保留的字符串,其他字符串必须从列表中删除,但我并不低估如何删除 static <T> Iterable<T> select(Iterable<T> it, Predicate<T> pred) { for (T s: it) { if (pred.test(s)==false) { // what to do here?
Iterable
和一个谓词来执行一个字符串列表过滤函数,以选择要保留的字符串,其他字符串必须从列表中删除,但我并不低估如何删除
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"}
由于任何
集合
都是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;
}
Iterable表示根据请求提供迭代器的能力。因此,要用过滤逻辑装饰现有的iterable,必须实现装饰
迭代器
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;
}
};
}
首先将您的Iterable
包装到流中
:
- 纯Java:
StreamSupport.stream(it.spliterator(), false)
-
-
然后根据您的谓词对其进行过滤:
最后返回Iterable
:
- 作为
lambda
:
return () -> stream.iterator();
- 作为
方法参考
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 Iterable select(Iterable it,Predicate pred){
返回StreamSupport.stream(it.spliterator(),false).filter(pred.negate())::迭代器;
}
或:
static Iterable select(Iterable it,Predicate pred){
Stream=Stream(it.spliterator(),false);
谓词negatedPred=pred.negate();
Stream filteredStream=Stream.filter(negatedPred);
返回filteredStream::迭代器;
}
我在评论中提到的霍尔格的替代方案如下所示:
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;
}
};
}
static Iterable select(Iterable到iterate,谓词pred){
return()->new Iterator(){
迭代器委托=toIterate.Iterator();
T next=findNextValid();
公共布尔hasNext(){
返回下一步!=null;
}
公共交通工具{
如果(next==null)抛出新的NoSuchElementException();
T结果=下一个;
next=findNextValid();
返回结果;
}
私有T findNextValid(){
T结果=null;
while(result==null&&delegate.hasNext()){
T candidate=delegate.next();
if(预备测试(候选)){
结果=候选人;
}
}
返回结果;
}
};
}
不同之处在于,hasCurrent
不需要额外的标记,它在实际请求下一个元素之前推进迭代器。你可能会认为后者是不受欢迎的。 PETEVE:<代码> PRED。测试(S)= = false < /COD>是坏的风格。使用!预先测试
Ty提示!顺便说一句,您想要的方法已经存在于Guava中:。检查它们的实现。这是一个解决方案,但不是一个有效的解决方案。最好实现一个能够跳过项的自定义迭代器——这就是Guava的实现所做的collection@GFAA所有Collection
s都是Iterable
s。他分配给Collection
,这样他就可以向其中添加项目。这样,我就可以检索列表或数组列表,而不是Collection和iterable了?@Michael是的,有很多方法。我不希望仅仅为了这个用例而导入番石榴。然而,用一个已经存在的实现来“启发”是一个很好的实践:)guava在内部使用一个AbstractIterator
解决了这个复杂的模式,该方法只有一个computeNext
方法IIRC;与tryAdvance
的想法几乎相同。这使得它们可以轻松实现Iterators::filter
。我想我更喜欢在next()
上推进源迭代器,而不是在hasNext()
中,然后存储“next”值或null
(如果没有可用)。也应该降低一点复杂性。@daniu这对通常的用例hasNext()
在next()
之前被调用并被要求给出正确的答案没有帮助。我可能没有正确解释,这就是我的意思:我刚刚意识到你的解决方案的行为(我的也一样)我不希望出现这样的行为:如果底层集合被修改(如在您的测试用例中),这将导致在更改之前返回的Iterable
发生更改。甚至在查询第一个元素之前就提前执行可能是一种令人惊讶的行为。但这并不是关于hasCurrent
字段的差异的原因。我的解决方案只是考虑源代码包含null
元素并且谓词接受它们的可能性。hasCurrent
标志用于正确处理该情况。如果排除null
,也可以在我的解决方案中用null
测试替换该字段。
Streams.stream(it)
StreamEx.of(it.iterator())
...
stream.filter(pred.negate())
...
return () -> stream.iterator();
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;
}
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;
}
};
}