如何实现`range()`

时间:2010-12-11 05:30:34

标签: java language-features range

简介

如何在Java 6中编写公共静态范围方法范围类,以便它至少涵盖在其他编程语言中实现的常用功能?

如果您想回答这个问题,那么您可以忽略以下内容。

<小时/>

关于

一次又一次,我错过了其他语言所具有的功能。对于我写的任何语言,我碰巧都有不同的编码风格,我不愿意改变这种习惯。所以,如果我想重用一种算法,我用不同的语言编写,那么我必须制作烦人的小黑客或变通办法来弥补缺失的功能。我想为range()找到永久有效的解决方案。

对我来说 - range()方法可能以惰性方式返回输入范围,并且它具有默认值。在任何时候它都有一个开始,一个结束的条件和一个获得下一个元素的方法。它应该在每个循环的中完美地工作。

备注

我真的不想使用任何外部库,除了谷歌番石榴或类似的。相当于我的意思是经过适当测试的代码,使用JDK可以很好地工作,并且不被视为已弃用。

alt text

可能不清楚,所以:

  • by How to write我的意思是 - 你不必写它,只描述常见的陷阱以及推荐方法的优点和缺点。
  • 这是loop code,但也可以使用
  • 这不是作业:P

除了整数输入,这将是最常用的功能,我真的希望它适用于类BigInteger和Joda DateTime的类型实例。

  • 必须能够在for-each循环
  • 中使用
  • 通用,但类型安全
  • 使用预先存在的容器方法,例如:.cycle(),. filter(),. all(),. any(),transform()

作为一种方法,range()标题可能如下所示:

/**TODO: Think about why / how to add step, limit, offset and cycle detection. */
public static <T extends Comparable<T>> Iterable<T> //
range(T from, Predicate<T> to, Function<T, T> fNext) //
        throws NullPointerException, IllegalArgumentException {

作为个人偏好,我已将Range编写为Builder模式实现。

修改

范围实施ScalaPython 3Groovy.Net (with linq) [c#, f#, vb and c++]rubyPHP ......所有这些都有所不同。< / p>

我不妨添加一个我想做的更好的例子(simple sample case)。

public static <T extends Comparable<T>> Iterable<T> //
range(T from, Predicate<T> to, Function<T, T> fNext) //
        throws NullPointerException {
    Preconditions.checkNotNull(from);
    Preconditions.checkNotNull(to);
    Preconditions.checkNotNull(fNext);

    T current = from;
    ArrayList<T> result = Lists.newArrayList();
    if (to.apply(current)) result.add(current);
    while (to.apply(current = Preconditions.checkNotNull(fNext.apply(current))))
        result.add(current);
    return result;
}

或懒惰的替代

//eats first element
public static <T extends Comparable<T>> Iterator<T> //
range2(final T from, final Predicate<T> to, final Function<T, T> fNext)
        throws NullPointerException, UnsupportedOperationException {
    Preconditions.checkNotNull(from);
    Preconditions.checkNotNull(to);
    Preconditions.checkNotNull(fNext);
    return new Iterator<T>() {
        T current = from;
        @Override public boolean hasNext() {return to.apply(current);}
        @Override public T next() {return current = Preconditions.checkNotNull(fNext.apply(current));}
        @Override public void remove() {throw new UnsupportedOperationException();}
    };
}

2 个答案:

答案 0 :(得分:1)

痛点可能是必须为每种类型编写函数:

  public static Function<Integer, Integer> intIncrementer(final int step) {
    class IntIncrementer implements Function<Integer, Integer> {
      private final int _step = step;

      @Override public Integer apply(Integer i) {
        return i + _step;
      }

      @Override public boolean equals(Object obj) {
        return (obj instanceof IntIncrementer) 
           && ((IntIncrementer) obj)._step == _step;
      }

      @Override public int hashCode() {
        return _step;
      }
    }

    return new IntIncrementer();
  }

由于无法以通用方式表达i + _step,因此您必须针对您希望支持的每种类型重新实现此功能(BigIntegerlong等。)< / p>

我会质疑是否需要使用<T extends Comparable<T>>而非<T>。我认为施加这种限制没有任何好处。

与集合不同,Iterable类型不会强制equality contract。如果您希望能够比较范围而无需外部迭代其所有元素,那么返回定义此类合同的Range类型可能会更好。

public interface Range<T> extends Iterable<T> {
  // TODO: write the terms of the contract
  @Override public boolean equals(Object obj);
  @Override public int hashCode();
  // TODO: other useful methods?
}

当涉及到原语时,创建包装器对象会产生开销。与仅使用传统的递增for循环相比,这可能在大范围内效率显着降低。

答案 1 :(得分:0)

我会选择最近的路径。创建一个这样的界面:

interface Steppable<T>{
    T defaultStep(); //Returns 1 for most number types
    T value(); //Returns the value itself
    Steppable<T> step(T amount); //the stepping logic
}

为范围函数(整数,长整数,日期等)中我想要使用的每种类型编写一大堆接口实现。然后为每个可行类型创建一个重载的range()函数,以便于使用。

我会采用这种方法,因为它可以直接添加更多可行的类型。至于缺点,这种方法有点冗长。