为算术系列做一个懒惰的迭代器?

时间:2011-04-26 20:17:53

标签: java iterator guava

这是我编写的implements Iterable<Integer>课程,用于算术系列课程(从startstop,步骤为step

package com.example.test;

import java.util.Iterator;
import com.google.common.collect.AbstractIterator;

public class ArithmeticSeries implements Iterable<Integer>
{
    final private int start, step, stop;
    public int getStart() { return this.start; } 
    public int getStep() { return this.step; } 
    public int getStop() { return this.stop; }

    public ArithmeticSeries(int start, int step, int stop)
    {
        this.start = start;
        this.step = step;
        this.stop = stop;
    }
    @Override public Iterator<Integer> iterator()
    {
        return new AbstractIterator<Integer>() {
            private Integer n = null;
            @Override protected Integer computeNext() {
                int next;
                if (this.n == null)
                {
                    next = getStart(); 
                }
                else
                {
                    next = this.n + getStep();
                    if ((getStep() > 0 && next > getStop()) 
                     || (getStep() < 0 && next < getStop()))
                        return endOfData();
                }
                this.n = next;
                return next;
            }
        };
    }
    @Override public String toString() {
        return getStart()+":"+getStep()+":"+getStop();
    }

    public static void main(String[] args) {
        Iterable<Integer> range = new ArithmeticSeries(100,-1,80);
        System.out.println(range);
        for (int i : range)
            System.out.println(i);
    }
}

有没有办法实现更优雅的iterator()?我不喜欢null检查和使用Integer(替代将是一个额外的标志boolean firstTime),它似乎是错误的。

3 个答案:

答案 0 :(得分:4)

return new AbstractIterator<Integer>() {
  int next = getStart();

  @Override protected Integer computeNext() {
    if (isBeyondEnd(next)) {
      return endOfData();
    }
    Integer result = next;
    next = next + getStep();
    return result;
  }
};

如果您愿意,您可以将其实现为不可变List<Integer>。如果您延长AbstractList,则Iterator会为您处理。实际上,我认为AbstractList真的是最好的方式。全班看起来像这样(我没有检查过它在所有情况下都能正常工作):

public class ArithmeticSeries extends AbstractList<Integer> {
  private final int start;
  private final int step;
  private final int size;

  public ArithmeticSeries(int start, int end, int step) {
    this.start = start;
    this.step = (start < end) ? step : -step;
    this.size = (end - start) / this.step + 1;
  }

  @Override public Integer get(int index) {
    return start + step * index;
  }

  @Override public int size() {
    return size;
  }
}

答案 1 :(得分:2)

您可以使用Function抽象连续值,使用Predicate控制迭代结束,最终创建Unfold实现:

public final class UnfoldIterator<E> implements Iterator<E> {
    public static <E> Iterator<E> unfold(E initial, Function<? super E, ? extends E> next, Predicate<? super E> finished) {
        return new UnfoldIterator<E>(initial, next, finished)
    }
    private final Function<? super E, ? extends E> next;
    private final Predicate<? super E> finished;
    private E element;

    public UnfoldIterator(E initial, Function<? super E, ? extends E> next, Predicate<? super E> finished) {
        super();
        this.next = next;
        this.finished = finished;
        this.element = initial;
    }
    @Override protected Integer computeNext() {
        if (finished.apply(element)) {
            return endOfData();
        }
        E result = element;
        element = next.apply(element);
        return result;
    }
}

然后ArithmeticSeries变为:

public Iterable<Integer> series(final int start, final int step, final int stop) {
    return new Iterable<Integer>() {
        public Iterator<Integer> iterator() {
            return new UnfoldIterator<Integer>(start, new Function<Integer, Integer>() {
                public Integer apply(Integer from) {
                    return from - step;
                }
            }, new Predicate<Integer>() {
                public boolean apply(Integer input) {
                    return input >= stop;
                }
            });
        }
    };
}

当然,代码现在似乎更复杂,但是通过适当的基本函数进行比较和代数,调用变得更加清晰:

return unfold(start, subtractBy(step), not(lessThan(stop)));

答案 2 :(得分:1)

我认为番石榴问题的最佳工具是AbstractLinkedIterator。您的示例的实现如下所示:

final Iterator<Integer> series = new AbstractLinkedIterator<Integer>(100) {

    @Override protected Integer computeNext(final Integer previous) {
        return previous == 80 ? null : previous - 1;
    }
};
while (series.hasNext()) {
    System.out.println(series.next());
}

您可以轻松地为此迭代器创建Iterable适配器,例如像这样:

package sk.the0retico.guava;

import java.util.Iterator;

import com.google.common.base.Function;
import com.google.common.collect.AbstractLinkedIterator;

public class LinkedIterable<T> implements Iterable<T> {

    public static final <T> Iterable<T> from(final T first,
        final Function<T, T> computeNext) {
        return new LinkedIterable<T>(first, computeNext);
    }

    public static void main(final String[] args) {
        final Iterable<Integer> series = LinkedIterable.from(100,
                                             new Function<Integer, Integer>() {

            @Override public Integer apply(final Integer input) {
                return input == 80 ? null : input - 1;
            }
        });
        for (final Integer value : series) {
            System.out.println(value);
        }
    }

    private final Function<T, T> computeNext;

    private final T first;

    public LinkedIterable(final T first, final Function<T, T> computeNext) {
        this.first = first;
        this.computeNext = computeNext;
    }

    @Override public Iterator<T> iterator() {
        return new AbstractLinkedIterator<T>(first) {

            @Override protected T computeNext(final T previous) {
                return computeNext.apply(previous);
            }
        };
    }
}

但是,这种方法对返回null的提供函数进行了特殊约束。