JAVAで、似たような構造が何度も出てきます。具体的には

int[] array={1,2,3,4,5,6,7};
のような配列に対して、ソートや中身の表示をするメソッドを作るときに、
for(int i=0;i<array.length;i++){
....
}
のような構造が各メソッド内にそれぞれ出てきます。ここを一つにまとめたいのですが、一般的にはどのように処理しますか?

回答の条件
  • 1人2回まで
  • 登録:2008/04/30 11:39:34
  • 終了:2008/05/07 11:40:02

回答(10件)

id:itss No.1

itss回答回数171ベストアンサー獲得回数12008/04/30 11:49:44

ポイント15pt

Hi,

java.util.ArrayListオブジェクトをつかうかも。

http://www.atmarkit.co.jp/fjava/javatips/140java030.html

id:yshkw

Hello

利点はイテレータなので、ループを使わないことでしょうか?

細かいことかもしれませんが、数値を比較したいときに

Integer.parseInt((String)array.get(i))<Integer.parseInt((String)array.get(i+1))</p>

のようにもっさりしませんか。勉強がてら、色々なソートの速度を比較する目的でコードを書く過程で、

ループを「まとめたい」と思ったのですが、他に方法はあったらよろしくお願いします。

2008/04/30 16:47:30
id:y-kawaz No.2

y-kawaz回答回数1421ベストアンサー獲得回数2262008/04/30 12:27:11

ポイント15pt

ソートやダンプなら、Javaの標準ライブラリに Arrays#sort や Arrays#toString が用意されていますよ。

http://java.sun.com/javase/6/docs/api/java/util/Arrays.html


配列に限定せずもう少し汎用的で少し気が効いたことをしたければ commons-lang に便利なクラス・メソッドがたくさんありますよ。

Jakarta Commons のライブラリは欲しいと思った関数が予想通りの名前で用意されていて使いやすいです。特に lang はかなり良く使いますね。

http://commons.apache.org/lang/

id:yshkw

ライブラリを教えていただきありがとうございます。Jakarta Commonsは実用の際は使ってみたいです。

ただ、今回は自分で基礎から勉強したいと思ってのことなので、あえて細かいところから作っています。

書き方が「一般的に」とか、よくなかったですね。

2008/04/30 12:46:28
id:ken33jp No.3

ken33jp回答回数928ベストアンサー獲得回数132008/04/30 15:54:57

ポイント15pt

ソートのアルゴリズムをいろいろ書いて調べたいけど、

スマートなソースはどういうのが理想かということですね。

『Javaによるアルゴリズム事典』サポートページ

http://oku.edu.mie-u.ac.jp/~okumura/java-algo/

ソースがダウンロードできますのでご利用ください。

そのソースが1つの答えです。

クイックソート、バブルソートとかのってたと思いますよ。

Javaによるアルゴリズム事典

本を買う必要はないと思います。

この本は、C言語アルゴリズム辞典という結構古い本のJava版です。

id:yshkw

もっと特殊です。リンク先のBubbleSort.javaの処理も、ShellSort.javaの処理も

for (int i = h; i < a.length; i++) {

...

}

のループ処理を持っています。このループ自体をメソッド等で共通化する方法を探しています。

2008/04/30 16:46:53
id:ita No.4

ita回答回数204ベストアンサー獲得回数482008/04/30 19:27:30

ポイント15pt
bool Data::loop(int *i)
{
    (*i)++;
    return (*i == length);
}


int i=0;
while (a.loop(&i))
{
   ...
}

とか?

二行になっちゃいますけど。

id:yshkw

なんだか近づいてきたみたいなんですが、JAVAではなさそう?

2008/05/05 01:49:10
id:lunlumo No.5

lunlumo回答回数107ベストアンサー獲得回数142008/04/30 23:55:40

ポイント15pt

 内容にもよると思いますが,共通化すべきものであれば,処理全体をクラスとして抽出してテンプレートメソッドパターンを適用する,ループの中で行う処理を分けてストラテジパターンを適用するといった辺りが定番でしょうか。

http://itpro.nikkeibp.co.jp/article/COLUMN/20060113/227236/?ST=d...

http://itpro.nikkeibp.co.jp/article/COLUMN/20060113/227233/?ST=d...

id:yshkw

もっとも聞きたいことに近い回答です。

ストラテジパターンですね。概念はなんとなくわかるのですが、

ここにforループを当てはめるとしたら・・・どうなるのでしょう?

たとえ勉強用といっても、forループは最小構成要素だから「共通化すべき」でない、と考えた方がいいのでしょうか?

2008/05/01 12:32:02
id:tarchan No.6

たーちゃん回答回数200ベストアンサー獲得回数22008/05/01 01:55:36

ポイント15pt

配列に対して一定の処理をほどこして結果を返すパターンというと java.io.FileFilter とかでしょうか。

もっと一般的なものだと ExecutorService で、マルチスレッドでタスクのコレクションを実行して結果を返すものがあります。

id:yshkw

ファイルやらパスの話ばかりに見えます。

下のはタスク管理系?パターンの具体例ということで上げてくださったのでしょうか?

やはり、質問が愚問だったのかな・・・。

http://q.hatena.ne.jp/1209523172#a824079

この回答が最も近いのですが、いかんせんC++です。

public void roop1(int[] array){

for(int i=0;i<5;i++){

System.out.print(array[i]);

}

}

public void roop2(int[] array){

for(int i=0;i<5;i++){

System.out.print(array[i]+",");

}

}

public void roop3(int[] array){

for(int i=0;i<5;i++){

System.out.println(array[i]);

}

}

のようにループの中身だけ微妙に異なるとき、何度もループを記述するのではなく、

abstract_roop(method1);

abstract_roop(method2);

abstract_roop(method3);

のようなことができないか?という質問です。

以下適当ですが、

public void abstract_roop(Method somemethod){

for(int i=0;i<5;i++){

somemethod(i);

}

}

public void method1(int i){

System.out.print(array[i]);

}

のような、メソッドを引数にとるメソッドってできるのでしょうか?

2008/05/01 12:51:03
id:lunlumo No.7

lunlumo回答回数107ベストアンサー獲得回数142008/05/02 00:22:49

ポイント15pt

> メソッドを引数にとるメソッドってできるのでしょうか?

 Javaの場合,現状クロージャの類は無いです。なので,振る舞いの違うクラスを切り替えて使うか,振る舞いを定義してクラスを指定する形で対応することになります。

・テンプレートパターンを使う場合

abstract class AbstractTemplate {
	int[]	data;
	
	void setData(int[] newData) { data = newData; }
	int[] getData() { return data; }
	
	AbstractTemplate(int[] newData) {
		data = newData;
	}
	
	abstract void doLoop(int value);
	
	public void loop() {
		int[]	data = getData();
		for (int i=0; i<data.length; i++) {
			doLoop(data[i]);
		}
	}
}

class PrintTemplate extends AbstractTemplate {
	PrintTemplate(int[] newData) { super(newData); }
	
	void doLoop(int value) {
		System.out.print(value);
	}
}
class CommaTemplate extends AbstractTemplate {
	CommaTemplate(int[] newData) { super(newData); }
	
	void doLoop(int value) {
		System.out.print(value + ",");
	}
}
class PrintlnTemplate extends AbstractTemplate {
	PrintlnTemplate(int[] newData) { super(newData); }
	
	void doLoop(int value) {
		System.out.println(value);
	}
}

public class Template {

	public static void main(String[] args) {
		int[] data = {1,2,3,4,5,6,7};
		
		new PrintTemplate(data).loop();
		new CommaTemplate(data).loop();
		new PrintlnTemplate(data).loop();
	}
}

・ストラテジパターンを使う場合

interface LoopStrategy {
	public void doLoop(int value);
}
class PrintStrategy implements LoopStrategy {
	public void doLoop(int value) {
		System.out.print(value);
	}
}
class CommaStrategy implements LoopStrategy {
	public void doLoop(int value) {
		System.out.print(value + ",");
	}
}

public class Strategy {

	int[] data;

	public void setData(int[] newData) { data = newData; }
	public int[] getData() { return data; }

	public void loop(LoopStrategy strategy) {
		int[] data = getData();

		for (int i = 0;i<data.length;i++) {
			strategy.doLoop(data[i]);
		}
	}

	public static void main(String[] args) {
		int[] data = {1,2,3,4,5,6,7};
		Strategy test = new Strategy();

		test.setData(data);

		test.loop(new PrintStrategy());
		test.loop(new CommaStrategy());
		test.loop(new LoopStrategy() {
			public void doLoop(int value) {
				System.out.println(value);
			}
		});
	}
}

 Java7ではクロージャが追加されるそうなので,もう少しスマートに書ける様になるでしょうか。参考までにRubyでの例を挙げておきます。

class LoopTest
	attr_accessor :data
	
	def loop
		data.each do |i|
			yield i
		end
	end
end

test = LoopTest.new

test.data = [1,2,3,4,5,6,7]

test.loop { |i| print i.to_s }
test.loop { |i| print i.to_s + "," }
test.loop { |i| puts i.to_s }

http://journal.mycom.co.jp/articles/2006/08/23/java7closuer/

id:yshkw

クロージャというんですね。漠然としたイメージを汲み取っていただきありがとうございます。

それから、デザインパターン例大変参考になります。

現在じっくりコーディングをしながら理解に励んでいるところです。

後日しっかり返信させていただきます。

2008/05/02 18:30:15
id:tera-p No.8

tera-p回答回数92ベストアンサー獲得回数212008/05/02 00:47:42

ポイント15pt

関数コールバックがやりたいのですね.Java では無名クラスを使って実装するのが一般的だと思います(メソッドが第一級オブジェクトではないため).

Java はここ数年触ってないので文法に間違いがあるかもしれませんが,こんな感じでできるはずです.

interface CallBack { public void callBack(int x) }

CallBack method1 = new CallBack () {

 public void callBack(int x) {

 // 実装その1

 }

}

CallBack method2 = new CallBack () {

 public void callBack(int x) {

 // 実装その2

 }

}

public void abstLoop(int[] array, CallBack obj) {

 for(int i=0; i<array.length; i++) {</p>

  obj.callBack(arrai[i]);

 }

}

// ここから本体

int[] array={1,2,3,4,5,6,7};

abstLoop(array, method1);

abstLoop(array, method2);

いかがでしょう.お望みのものに近いでしょうか.

#Java の場合,記述量がどうしても増えてしまいますが….

id:yshkw

デザインパターンではないやり方もあるんですね。

直感に近いので、デザインパターンを理解できたらこれを試してみようと思います。

コールバックというフレーズは良く聞きますが、実感を伴わなかったのでこれを機に身につけようと思います。

2008/05/02 18:32:43
id:finky No.9

finky回答回数1ベストアンサー獲得回数02008/05/02 02:05:48

ポイント15pt

http://java.sun.com/javase/ja/6/docs/ja/api/java/lang/reflect/Me...

おそらく、イメージされているのに一番近いのは、リフレクトを使ってメソッドを呼び出す方法だと思います。

void loopCall(int[] ar, String name) { //実際には例外を投げますが省略

Method method = this.getClass().getMethod(name, int.class);

for (int i : ar) {

method.invoke(this, i); //staticメンバーのとき第1パラメタはnull

}

}

というようなメソッドを用意して、

void printValue(int i) {

System.out.print(i);

}

というメソッドをループで呼び出すときには、

int[] data = {1, 2, 3, 4, 5};

this.loopCall(data, "printValue");

というコードになります。

id:yshkw

デザインパターン、コールバック以外にも方法があるのですね。

こちらも実装しながら理解してみようと思います。

GWは忙しくなりそうです

2008/05/02 18:33:44
id:tera-p No.10

tera-p回答回数92ベストアンサー獲得回数212008/05/03 03:36:17

ポイント15pt

8 で回答した者です.

デザインパターンではないやり方もあるんですね。

とのことですが,デザインパターンというのは,「よく使われる便利なプログラミングテクニック」に「名前をつけた」ものになります.一方,コールバックは「よく使われる便利なプログラミングテクニック」の有力な構成要素であり,各種デザインパターンの中でも多用されます.実際,回答 7 の Strategy パターンの例は,コールバックを内部で使ってらっしゃいます(test.loop() の引数でコールバックメソッド(を備える Strategy オブジェクト;Java なのでこのひと手間が必要)を渡しています).また,よく見ると,回答 7 の(Strategyパターンの)コードと,回答 8 の私のコードは,本質的にはほとんど同じことをやっていることがわかると思います(私の回答時は回答 7 がまだオープンではなかったので,かなり内容が被ってしまっています).回答 7 は Strategy パターンに忠実なコードで,回答 8 は無名クラスという Java 特有の別のテクニックを併用している,という差異はありますが.

以下,ちょっと蛇足です.

ご質問のようなことは,Java でやろうとすると回答 7, 8のようにかなり冗長になりますが,Python や Ruby など関数を引数として渡せる(関数が第一級オブジェクトな)言語では,map と呼ばれる LISP 由来の機能を使ってとても簡単にできます.

Ruby は回答 7 でイテレータを使った例が提示されていますので,私からは Python で map を使った例を:

def method1(x): print x

def method2(x): print x*2

def method3(x): print x*3

array = [1,2,3,4,5,6,7]

map(method1,array)

map(method2,array)

map(method3,array)

というようにめんどくささが全然違います(ので,私は Java からは足を洗って Python な人になってしまいました).

  • id:yshkw
    あ、締め切り過ぎてしまいました・・・。
    lunlumoさんに追加で30ポイント送信します。
    tera-pさんは、もう一つの質問の方で加味したいと思います。
    >>10の追加説明は大変参考になりました。色々わかると楽しいですね。
    他の方もありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません