Genericsを使うJava用のmap, filter, foldなど。
いちいちfor文を書くのに疲れてきたので、書いてみた。
ノーコメントですまそ。
map, filter, foldを実装。
/** * High-order functions for Java collections. */ public class CollectionUtil { public static <T0, T1> List<T1> map(Collection<T0> collection, Function<T0, T1> each) { List<T1> result = new ArrayList<T1>(collection.size()); for (T0 element : collection) { result.add(each.apply(element)); } return result; } public static <T0> List<T0> filter(Collection<T0> collection, Function<T0, Boolean> each) { List<T0> result = new ArrayList<T0>(); for (T0 element : collection) { if (each.apply(element)) result.add(element); } return result; } public static <T0, T1> T1 foldLeft(Collection<T0> collection, Procedure<T0, T1> each) { for (T0 element : collection) { each.apply(element); } return each.get(); } }
各要素に対して適用する関数。
/** * Function that returns value of type B using value of type A. */ public interface Function<A, B> { public B apply(A element); }
各要素に対して適用し、その結果を保持することが可能な手続き。
/** * Foldable has a function and a state (like a closure). */ public interface Procedure<A, B> extends Function<A, B> { public B get(); }
で、これができると、こういうことができるようになります。例えば1から10の整数に対する総和を返す場合。でも各計算結果を保持するためには1個名前付きのクラスを用意しなければ状態の保持しどころがないので難しい…。
1つ、参照渡しのようなイメージの引数を渡して、そこに状態を保持させる作戦とかどうだろう。それならできるかな?
class Sum implements Procedure<Integer, Integer> { private Integer value; Sum (Integer initial) { this.value = initial; } public Integer apply(Integer element) { value += element.intValue(); return value; } public Integer get() { return Integer.valueOf(value); } } @Test public void testFold() { List<Integer> oneToTen = Arrays.<Integer>asList(1,2,3,4,5,6,7,8,9,10); assertEquals(Integer.valueOf(55), CollectionUtil.foldLeft(oneToTen, new Sum(0))); }
mapやfilterなんかは簡単なんだけど、各要素の計算結果を保持するライブラリとして持っておきたいな。もっと考慮すべき点はあるかな。