int[] array={1,2,3,4,5,6,7};
のような配列に対して、ソートや中身の表示をするメソッドを作るときに、
for(int i=0;i<array.length;i++){
....
}
のような構造が各メソッド内にそれぞれ出てきます。ここを一つにまとめたいのですが、一般的にはどのように処理しますか?
ソートやダンプなら、Javaの標準ライブラリに Arrays#sort や Arrays#toString が用意されていますよ。
http://java.sun.com/javase/6/docs/api/java/util/Arrays.html
配列に限定せずもう少し汎用的で少し気が効いたことをしたければ commons-lang に便利なクラス・メソッドがたくさんありますよ。
Jakarta Commons のライブラリは欲しいと思った関数が予想通りの名前で用意されていて使いやすいです。特に lang はかなり良く使いますね。
ライブラリを教えていただきありがとうございます。Jakarta Commonsは実用の際は使ってみたいです。
ただ、今回は自分で基礎から勉強したいと思ってのことなので、あえて細かいところから作っています。
書き方が「一般的に」とか、よくなかったですね。
ソートのアルゴリズムをいろいろ書いて調べたいけど、
スマートなソースはどういうのが理想かということですね。
『Javaによるアルゴリズム事典』サポートページ
http://oku.edu.mie-u.ac.jp/~okumura/java-algo/
ソースがダウンロードできますのでご利用ください。
そのソースが1つの答えです。
クイックソート、バブルソートとかのってたと思いますよ。
本を買う必要はないと思います。
この本は、C言語アルゴリズム辞典という結構古い本のJava版です。
もっと特殊です。リンク先のBubbleSort.javaの処理も、ShellSort.javaの処理も
for (int i = h; i < a.length; i++) {
...
}
のループ処理を持っています。このループ自体をメソッド等で共通化する方法を探しています。
bool Data::loop(int *i) { (*i)++; return (*i == length); } int i=0; while (a.loop(&i)) { ... }
とか?
二行になっちゃいますけど。
なんだか近づいてきたみたいなんですが、JAVAではなさそう?
内容にもよると思いますが,共通化すべきものであれば,処理全体をクラスとして抽出してテンプレートメソッドパターンを適用する,ループの中で行う処理を分けてストラテジパターンを適用するといった辺りが定番でしょうか。
http://itpro.nikkeibp.co.jp/article/COLUMN/20060113/227236/?ST=d...
http://itpro.nikkeibp.co.jp/article/COLUMN/20060113/227233/?ST=d...
もっとも聞きたいことに近い回答です。
ストラテジパターンですね。概念はなんとなくわかるのですが、
ここにforループを当てはめるとしたら・・・どうなるのでしょう?
たとえ勉強用といっても、forループは最小構成要素だから「共通化すべき」でない、と考えた方がいいのでしょうか?
配列に対して一定の処理をほどこして結果を返すパターンというと java.io.FileFilter とかでしょうか。
もっと一般的なものだと ExecutorService で、マルチスレッドでタスクのコレクションを実行して結果を返すものがあります。
ファイルやらパスの話ばかりに見えます。
下のはタスク管理系?パターンの具体例ということで上げてくださったのでしょうか?
やはり、質問が愚問だったのかな・・・。
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]);
}
のような、メソッドを引数にとるメソッドってできるのでしょうか?
> メソッドを引数にとるメソッドってできるのでしょうか?
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/
クロージャというんですね。漠然としたイメージを汲み取っていただきありがとうございます。
それから、デザインパターン例大変参考になります。
現在じっくりコーディングをしながら理解に励んでいるところです。
後日しっかり返信させていただきます。
関数コールバックがやりたいのですね.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 の場合,記述量がどうしても増えてしまいますが….
デザインパターンではないやり方もあるんですね。
直感に近いので、デザインパターンを理解できたらこれを試してみようと思います。
コールバックというフレーズは良く聞きますが、実感を伴わなかったのでこれを機に身につけようと思います。
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");
というコードになります。
デザインパターン、コールバック以外にも方法があるのですね。
こちらも実装しながら理解してみようと思います。
GWは忙しくなりそうです
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 な人になってしまいました).
Hello
利点はイテレータなので、ループを使わないことでしょうか?
細かいことかもしれませんが、数値を比較したいときに
Integer.parseInt((String)array.get(i))<Integer.parseInt((String)array.get(i+1))</p>
のようにもっさりしませんか。勉強がてら、色々なソートの速度を比較する目的でコードを書く過程で、
ループを「まとめたい」と思ったのですが、他に方法はあったらよろしくお願いします。