プログラマとプロマネのあいだ

プログラマもやるし、プロマネもやるし、たまに似非アーキとか営業っぽいこともやる

Javaでmapメソッド(改良)

前回のはint型の配列にしか対応してなかったので、全型に対応できるようにしてみた。
前回の: http://d.hatena.ne.jp/taka_2/20071220#p1

さすがにjava.lang.reflect.Methodはないだろうと思い、interfaceを定義してそれを実装することでmapメソッド中の処理を実装するようにした。

下記の例では、PlusOneProcessMapクラスが、処理内容を定義している。(Rubyのmap/collectメソッドでいうところのブロックの内部に相当)

便宜上NumericProcessMapというAdapterクラスを定義し、数値を扱うプリミティブ型をまとめて扱えるようにした。この結果、PlusOneProcessMapクラスでは、doubleを扱う処理のみ記述することでintやfloatにも対応できたことになる。

import java.lang.reflect.Array;

/*
 * javaでmapメソッドを実現するテスト
 */
public class maptest
{
	/*
     * mapメソッドで処理する方法を定めるインタフェース
     */
	interface ProcessMap
	{
		public boolean processMap(boolean data);
		public byte    processMap(byte    data);
		public char    processMap(char    data);
		public double  processMap(double  data);
		public float   processMap(float   data);
		public int     processMap(int     data);
		public long    processMap(long    data);
		public short   processMap(short   data);
		public Object  processMap(Object  data);
	}

	/*
     * 配列と処理を渡すと、配列の各要素に対してそれぞれ処理を行った結果の配列を返す。
     * 配列を渡さない場合は、そのオブジェクトをそのまま返却する。
     */
	public Object map(Object arrObj, ProcessMap pm)
	{
		// 渡されたオブジェクトが配列でない場合は、そのまま返却する。
		if(!arrObj.getClass().isArray())
		{
			return arrObj;
		}

		// 渡された配列の型
		Class componentType = arrObj.getClass().getComponentType();
		// 渡された配列のサイズ
		int size = Array.getLength(arrObj);

		// 渡された配列と同じ型、同じサイズの配列オブジェクトを生成する。
		Object result = Array.newInstance(componentType, size);

		// 配列の各要素について、processMapメソッドを実行し、結果をresultへ格納する。
		for(int i=0; i<size; i++)
		{
			if(componentType.equals(Boolean.TYPE))
			{
				Array.setBoolean(result, i, pm.processMap(Array.getBoolean(arrObj, i)));
			}
			else if(componentType.equals(Byte.TYPE))
			{
				Array.setByte(result, i, pm.processMap(Array.getByte(arrObj, i)));
			}
			else if(componentType.equals(Character.TYPE))
			{
				Array.setChar(result, i, pm.processMap(Array.getChar(arrObj, i)));
			}
			else if(componentType.equals(Double.TYPE))
			{
				Array.setDouble(result, i, pm.processMap(Array.getDouble(arrObj, i)));
			}
			else if(componentType.equals(Float.TYPE))
			{
				Array.setFloat(result, i, pm.processMap(Array.getFloat(arrObj, i)));
			}
			else if(componentType.equals(Integer.TYPE))
			{
				Array.setInt(result, i, pm.processMap(Array.getInt(arrObj, i)));
			}
			else if(componentType.equals(Long.TYPE))
			{
				Array.setLong(result, i, pm.processMap(Array.getLong(arrObj, i)));
			}
			else if(componentType.equals(Short.TYPE))
			{
				Array.setShort(result, i, pm.processMap(Array.getShort(arrObj, i)));
			}
			else
			{
				// primitive型ではない。
				Array.set(result, i, pm.processMap(Array.get(arrObj, i)));
			}
		}

		return result;
	}

	/*
     * 数値型に対するmap処理
     * boolean, char, Objectはそのまま返します。
     */
	class NumericProcessMap implements ProcessMap
	{
		public boolean processMap(boolean data)
		{
			return data;
		}

		public byte    processMap(byte    data)
		{
			return (byte)processMap((double)data);
		}

		public char    processMap(char    data)
		{
			return data;
		}

		public double  processMap(double  data)
		{
			return data;
		}

		public float   processMap(float   data)
		{
			return (float)processMap((double)data);
		}

		public int     processMap(int     data)
		{
			return (int)processMap((double)data);
		}

		public long    processMap(long    data)
		{
			return (long)processMap((double)data);
		}

		public short   processMap(short   data)
		{
			return (short)processMap((double)data);
		}

		public Object  processMap(Object  data)
		{
			return data;
		}
	}

	class PlusOneProcessMap extends NumericProcessMap
	{
		public double processMap(double data)
		{
			return data + 1;
		}
	}

	/*
     * テストドライバ
     */
	public static void main(String[] args)
	{
		new maptest();
	}

	public maptest()
	{
		int[] iArray = {1, 2, 3};
		float[] fArray = {2.2f, 3.3f, 4.4f};

		PlusOneProcessMap popm = new PlusOneProcessMap();

		int[] iArrayMapped = (int[])map(iArray, popm);
		float[] fArrayMapped = (float[])map(fArray, popm);

		System.out.println("-- iArray map前 --");
		printArray(iArray);

		System.out.println("-- iArray map後 --");
		printArray(iArrayMapped);

		System.out.println("-- fArray map前 --");
		printArray(fArray);

		System.out.println("-- fArray map後 --");
		printArray(fArrayMapped);
	}

	private void printArray(Object arr)
	{
		for(int i=0; i<Array.getLength(arr); i++)
		{
			System.out.println(i + ":" + Array.get(arr, i));
		}
	}
}

これの結果は以下のように表示される。

>java maptest
-- iArray map前 --
0:1
1:2
2:3
-- iArray map後 --
0:2
1:3
2:4
-- fArray map前 --
0:2.2
1:3.3
2:4.4
-- fArray map後 --
0:3.2
1:4.3
2:5.4

>