JavaでLL言語のようにリスト(配列)を操作したい
Lisp発祥かと思いますが、LL言語でリストor配列を扱う関数orメソッドのようなことを、Javaでやりたい場合はどうやるのが一般的なのでしょうか。
具体的にはRubyで例を挙げてみますが、
ia = [3, 2, 7] p( ia.select() do |item| item >= 3 end ) # => [3, 7] p( ia.inject() do |result, item| result + item end )# => 12 sa = %w[tw el ve] p( sa.grep(/[tv]/) ) # => ["tw", "ve"] p( sa.select() do |item| item.include?("e") end ) # => ["el", "ve"] p( sa.inject() do |result, item| result + item end )# => "twelve" oa = [12.0, Time.new, "13", 14] p( oa.select() do |item| item.is_a?(Numeric) end ) # => [12.0, 14]
のような処理です。
ここでは、RubyのEnumerableのインタフェースを参考に、それっぽいのをJava(5.0対応)で作ってみました。まだ途中ですが、ちょっと長めです。
まずは本体。
import java.util.*; import java.util.regex.*; abstract class Enumerable<E> { interface Selectable<E> { boolean select(E e); } interface Injectable<E> { E inject(E result, E e); } public Array<E> grep(Pattern pattern) { return grep(pattern, new Selectable<E>() { public boolean select(E e) { return true; } }); } public Array<E> grep(final Pattern pattern, final Selectable<E> selectable) { return each(new Selectable<E>() { public boolean select(E e) { if (e != null) { return pattern.matcher(e.toString()).find() && selectable.select(e); } return false; } }); } public Array<E> select(Selectable<E> selectable) { return each(selectable); } public E inject(Injectable<E> injectable) { return inject(injectable, null); } public E inject(Injectable<E> injectable, E initialValue) { return each(injectable, initialValue); } // public abstract Array<E> sort(); // public abstract Array<E> sort(Comparable<E> comparable); /* each */ public abstract Array<E> each(Selectable<E> selectable); public abstract E each(Injectable<E> injectable, E initialValue); } class Array<E> extends Enumerable<E> { private List<E> list; public Array() { this.list = new ArrayList<E>(); } public Array(E[] objects) { this(Arrays.asList(objects)); } public Array(Collection<E> collection) { this.list = new ArrayList<E>(collection); } public static <E> Array<E> valueOf(E... objects) { return new Array<E>(objects); } public boolean add(E e) { return list.add(e); } public E get(int index) { return list.get(index); } public int size() { return list.size(); } @Override public String toString() { return list.toString(); } @Override public Array<E> each(Selectable<E> selectable) { Array<E> array = new Array<E>(); for (E e : list) { if (selectable.select(e)) { array.add(e); } } return array; } @Override public E each(Injectable<E> injectable, E initialValue) { E result = initialValue; boolean isFirst = true; for (E e : list) { if (isFirst) { if (result == null) { result = e; continue; } isFirst = false; } result = injectable.inject(result, e); } return result; } }
テストコード。
Array<Integer> ia = Array.valueOf(3, 2, 7); System.out.println(ia.select(new Enumerable.Selectable<Integer>() { public boolean select(Integer item) { return item >= 3; } })); System.out.println(ia.inject(new Enumerable.Injectable<Integer>() { public Integer inject(Integer result, Integer item) { return result + item; } })); Array<String> sa = Array.valueOf("tw", "el", "ve"); System.out.println(sa.grep(Pattern.compile("[tv]"))); System.out.println(sa.select(new Enumerable.Selectable<String>() { public boolean select(String item) { return item.indexOf('e') >= 0; } })); System.out.println(sa.inject(new Enumerable.Injectable<String>() { public String inject(String result, String item) { return result + item; } })); Array<Object> oa = Array.valueOf(12.0, (Object)new Date(), "13", 14); System.out.println(oa.select(new Enumerable.Selectable<Object>() { public boolean select(Object item) { return (item instanceof Number); } })); // おまけ System.out.println(Array.valueOf("A", "B").grep(Pattern.compile("A")));
全体的に見づらいですが、意味重視ということで。他のメソッドも同じ要領で作れそうです。ファクトリはもうちょっときれいにしたいところですが、時間切れのため次回に。
実行結果です。
[3, 7] 12 [tw, ve] [el, ve] twelve [12.0, 14] [A]