- PR -

多次元配列(?)の長さを取得したい場合

投稿者投稿内容
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-13 14:46
ありがとうございます!

早速作ってみました。うまくいきました。

で、ついでにこれの応用で、プリミティブの型用の物もつくろうと、getCountの同一名称
で引数を int[] に変更してみたところNGでした。

array[i] instanceof int[] でコンパイル時にエラーが出てしまいました。

検出値 : int
期待値 : int[]

プリミティブの型を実行時に判定するには無理があるので仕方がないかな?
一瞬、配列もオブジェクトじゃねーか?と思ったのだが、あきらめよう。

<ソース>
class countArray{
public static int getCount(Object[] array) {
int count = 0;
for( int i = 0;i < array.length; i ++ ){
if( array[i] instanceof Object[] ){
count += getCount((Object[])array[i]);
}else{
count = array.length;
}
}
return count;
}

public static void main(String[] args){

String[] a = new String[10];
String[][] b = new String[20][30];
String[][][] c = new String[30][40][50];
String[] d1 = new String[60];
String[] d2 = new String[70];
String[] d3 = new String[80];
String[][] d = { d1, d2, d3 };

System.out.println("a:"+getCount(a));
System.out.println("b:"+getCount(b));
System.out.println("c:"+getCount(c));
System.out.println("d:"+getCount(d));

}
}

<結果>
a:10
b:600
c:60000
d:210


[ メッセージ編集済み 編集者: maru 編集日時 2003-03-13 15:11 ]
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-13 15:26
引用:

unibonさんの書き込み (2003-03-13 14:46) より:
要素のアクセスに掛け算を使うようにしたほうが良いかも
配列の配列を使うよりは自然かも


こんにちは。返答ありがとうございます。
確かに、配列の配列の・・・(以下続く)は、配列の参照の配列の参照・・・(以下続く)
なので、掛け算のコストに比べて遅いかもしれませんね。(どれほどかわかんないけど)

巨大な座標データなどを配列に落とし込む場合は、多次元配列に落とすより、1次元配列
に落としてアクセスしたほうがいいでしょうね。

ただ今回は、どちらかといえば配列を作る(newする)側ではなくて、配列を受け取って処理
する側のクラスを作っていて、(オブジェクト指向チックに)汎用的に使えるように考えて、
もらう配列の次元数に固定しない処理の方がいいかな?と思って、疑問に思ったのでした。

どちらも一長一短で場合によって使い分けですね。


[ メッセージ編集済み 編集者: maru 編集日時 2003-03-13 15:29 ]
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-03-13 15:40
unibon です。こんにちわ。

引用:

maruさんの書き込み (2003-03-13 15:26) より:
ただ今回は、どちらかといえば配列を作る(newする)側ではなくて、配列を受け取って処理
する側のクラスを作っていて、(オブジェクト指向チックに)汎用的に使えるように考えて、
もらう配列の次元数に固定しない処理の方がいいかな?と思って、疑問に思ったのでした。


私も、引数に配列の配列を渡してもらうようなメソッドを作っている際に、
maruさんと同じ疑問を持ったことはあります。
で、そのときは a[0].length だけを見る(その他の a[1].length などは見ない)、
という仕様で逃げてしまいました。

この問題は、matrix 関連を扱うかたなら誰もが広く共通して持つ問題だと思うので、
なにかもっと良い解法のパターンがあってもよさそうな気がしますが、
私はいまだに見つけられません。
#JDK のソースコードなどを見たらよいのかな、と思っていますが。
jack_pma
常連さん
会議室デビュー日: 2002/11/15
投稿数: 35
お住まい・勤務地: 埼玉
投稿日時: 2003-03-13 15:44
失礼しました、確かにint[]はinstanceof Object[]ではダメみたいですね。
そこで、ClassのisArrayで判断してreflectパッケージのArrayでアクセスするという方法をちょっと試してみました。

コード:
    public int countArray(Object ary){

        if (!ary.getClass().isArray())return 0;

        int len = Array.getLength(ary);
    // この配列の長さを(仮の要素数として)取る
        int cnt = len;

        for (int i=0; i<len; i++){
            Object obj = Array.get(ary, i);
            if (obj != null){
            // Object[] は配列と他の値を同時に突っ込めるので、配列が来たら減算
                if (obj.getClass().isArray()){
                    cnt--;
                    cnt +=countArray(obj);
                }
            }
        }
        return cnt;
    }



こんな具合になりました。
厄介なのは、Object[]が来ると要素が配列だったり配列じゃなかったりする、というところで、配列を見つけたらその分だけ減算させました。
役に立つかは解らないけど、これで当初の目的は達成できますかね?
BBC
常連さん
会議室デビュー日: 2002/03/15
投稿数: 37
お住まい・勤務地: 東京
投稿日時: 2003-03-13 15:47
R−55さんの書き込み(2003-03-13 15:26)より
引用:

int[] a = new int[2];
int[][] b = { {0,1,2}, a};

のような場合も考慮するとやはりmaruさんの方法しか無いような気がします。


あ(汗)、個別に処理できるのを忘れてました。

個人的には、メンバとしてクラスの中に隠蔽しちゃう癖があるので、
1次元配列×nで済ましちゃう事が多いですね。


#単純な配列を返してもらうよりは、java.util.Collection関連のオブジェクトを
#投げてもらう方が、キレイかな・・・とは思ったり。
maru
ぬし
会議室デビュー日: 2003/01/27
投稿数: 412
投稿日時: 2003-03-13 16:25
こんにちは。みなさん、ありがとうございました。

jack_pmaさんの案も盛り込んで、以下のようなクラスができました。
本当は、getCountメソッドをオーバーロードで、共通名で作りたかったのですけど、
コンパイルはとおるのですが、なぜか結果が正しくありませんでした。
プリミティブ型の方のgetCountをコールすると、メソッドの中の再帰処理でクラス型の
方のgetCountを呼んでいるのかな?
あいまいなコードがかけないはずのjavaであいまいな処理をさせてしまっているのかな?

当初は、この議題はそんなに深く考えていなかったのですけど、結構勉強になりました。
今回作ったクラスは実際に使うかは分からないけど(すいません)、今後の参考になると
思います。

<ソース>
import java.lang.reflect.Array;

class countArray{
/* クラス型配列 */
public static int getCount(Object[] array) {
int count = 0;
for( int i = 0;i < array.length; i ++ ){
if( array[i] instanceof Object[] ){
count += getCount((Object[])array[i]);
}else{
count = array.length;
}
}
return count;
}
/* プリミティブ型配列 */
public static int getCount2(Object ary){
if (!ary.getClass().isArray())return 0;
int len = Array.getLength(ary);
int cnt = len;
for (int i=0; i<len; i++){
Object obj = Array.get(ary, i);
if (obj != null){
if (obj.getClass().isArray()){
cnt--;
cnt +=getCount2(obj);
}
}
}
return cnt;
}

public static void main(String[] args){

String[] a = new String[10];
String[][] b = new String[20][30];
String[][][] c = new String[30][40][50];
String[] d1 = new String[60];
String[] d2 = new String[70];
String[] d3 = new String[80];
String[][] d = { d1, d2, d3 };
int[] e = new int[100];
int[][] f = new int[20][30];
double[] g = new double[40];
float[][] h = { new float[40], new float[50], new float[60]};

System.out.println("a:"+getCount(a));
System.out.println("b:"+getCount(b));
System.out.println("c:"+getCount(c));
System.out.println("d:"+getCount(d));
System.out.println("e:"+getCount2(e));
System.out.println("f:"+getCount2(f));
System.out.println("g:"+getCount2(g));
System.out.println("h:"+getCount2(h));

}
}

<結果>
a:10
b:600
c:60000
d:210
e:100
f:600
g:40
h:150

スキルアップ/キャリアアップ(JOB@IT)