3

私は、Java の配列に関する質問があるかなり初心者のプログラマーです。2D 配列 [i][j] を考えてみましょう。i の値は実行時に決定されます。j の値は 7 であることがわかっています。[i][6] と [i][7] で、より深い配列または値のリストを格納できるようにしたいと考えています。[i][6]とi[7]の点にx軸とy軸とz軸がある配列内に配列のようなものを持つことは可能ですか、それとも完全な3Dキューブのメモリが必要ですか?データを保存してナビゲートできますか?

詳細:私の目標は、2 つのテーブル (ターゲットと攻撃者) から特定の情報を取得するクエリを実行することです。クエリは問題なく、結果セットを取得できます。私が本当にやりたいことは、結果セットからのデータを保存し、それをデータ視覚化プログラムで使用しながら、より便利な形式でテーブルに表示することです。取得するフィールドは、server_id、target_ip、threat_level、client_id、attacker_ip、および num_of_attacks です。そのマシンは 20 回攻撃されたため、server_id、target_ip、threat_level、client_id が同じで、attacker_ip と num_of_attacks が異なる 20 のレコードを取得できました。3 番目の次元でこれを行うことができますが、server_id、target_ip、threat_level、client_id の 3 番目の軸/配列は空になります。

回答を確認し、さらに考えた後、 UPDATEオブジェクトの配列リストを使用することが私にとって最適かどうか、および/または可能かどうか疑問に思っています。データを整理して簡単にアクセスできるようにすることは、私にとって大きな関心事です。疑似コードでは、次のようになります。

Object[] servers
    String server_id
    String target
    String threat_level
    String client_id
    String arr[][]   // this array will hold attacker_ip in one axis and num_of_attacks in the other in order to keep the relation between the attacking ip and the number of attacks they make against one specific server
4

3 に答える 3

4

まず、配列がDataType[i][j]ありj、7 であることがわかっている場合、使用できる 2 つの最大のインデックスは 6 と 7 ではなく、5 と 6 です。これは、Java 配列インデックスが 0 ベースであるためです。配列を作成するときは、最大インデックス (常に要素数より 1 少ない数) ではなく、要素数を指定します。

第 2に、問題のドメインで既に使用されている多次元配列を使用しても問題はありません。科学的な応用やデータ分析の応用は考えられますが、それ以上のものはありません。反対に、ドメインが多次元配列を使用しないビジネス上の問題をモデル化している場合は、配列が非常に効率的であるように見えるという理由だけで、設計に配列を強制するのではなく、より抽象的なデータ構造を使用する方がおそらく良いでしょう。配列が使用される他の言語での経験より重要な理由、またはその他の理由。

List多くの情報がなくても、「最初の次元」は型 (たとえば)でより適切に表現できると思いますArrayList。なんで?そのサイズは実行時に決定されると言うからです(これは、どこかから取得した魔法の数としてではなく、間接的に来ると思います)。 Lists は配列に似ていますが、拡張方法を「知っている」という特殊性があります。プログラムは、ソースから新しい要素を読み取るか、その他の方法でそれらを検出/作成するときに、新しい要素を簡単に追加できます。冒頭や途中でも簡単に挿入できますが、これはまれです。

したがって、最初の次元は次のようになります: ArrayList<something>、ここで、somethingは 2 番目の次元の型です。

この 2 番目のディメンションに関して、サイズは 7 ですが、最初の 5 つの項目は単一の値を受け入れ、最後の 2 つの項目は複数の値を受け入れると言っています。これは、7 つの項目が同種ではないことをすでに示しているため、配列は適切に示されていません。この次元は、クラスによってより適切に表現されます。このクラスの構造を理解するために、5 つの単一値要素が同種であるとしましょう (たとえば、型BigDecimal)。これの最も自然な表現の 1 つは、サイズが既知であるため、配列です。残りの 2 つの多値要素も配列を構成しているようです。ただし、その 2 つの要素のそれぞれに未確認の数のデータ項目が含まれていることを考えると、この配列の要素の型はBigDecimal前のケースのようにすべきではありませんが、 ArrayList. これらの要素の型ArrayLists は、複数の値の型が何であれ (BigDecimal同様に) です。

最終結果は次のとおりです。

class SecondD {
    BigDecimal[] singleValued= new BigDecimal[5] ;
    ArrayList<BigDecimal>[] multiValued= new ArrayList<BigDecimal>[2] ;
    {
        multiValued[0]= new ArrayList<BigDecimal>() ;
        multiValued[1]= new ArrayList<BigDecimal>() ;
    }
}
ArrayList<SecondD> data= new ArrayList<SecondD>() ;

このコード スニペットでは、構造を宣言するだけでなく、すぐに使用できるように構造を作成しています。純粋な宣言は次のようになります。

class SecondD {
    BigDecimal[] singleValued;
    ArrayList<BigDecimal>[] multiValued;
}
ArrayList<SecondD> data= new ArrayList<SecondD>() ;

Java では、型 (および構造) の観点から、配列のサイズは重要ではありません。そのため、5 または 2 は表示されません。

データ構造へのアクセスは次のようになります

data.get(130).singleValued[2]
data.get(130).multiValued[1].get(27)

特定のケースでより明確になる可能性のあるバリアントは次のとおりです。

class SecondD {
    BigDecimal monday;
    BigDecimal tuesday;
    BigDecimal wednesday;
    BigDecimal thursday;
    BigDecimal friday;
    ArrayList<BigDecimal> saturday= new ArrayList<BigDecimal>() ;
    ArrayList<BigDecimal> sunday= new ArrayList<BigDecimal>() ;
}
ArrayList<SecondD> data= new ArrayList<SecondD>() ;

この場合、各配列を個々の項目に「展開」し、それぞれに名前を付けます。一般的なアクセス操作は次のとおりです。

data.get(130).wednesday
data.get(130).sunday.get(27)

どのバリアントを選択しますか? まあ、それは、さまざまなアイテムでの操作がどの程度類似しているか、または異なるかによって異なります。実行するたびに、、 、、およびを使用して操作するmonday場合(そうではなく、これらはまったく異なる種類のものであるため、覚えていますか?)、配列の方が優れている可能性があります。たとえば、配列として格納するときにアイテムを合計するには、次のようにするだけです。tuesdaywednesdaythursdayfridaysaturdaysunday

element= data.get(130) ;
int sum= 0 ;
for(int e: element.singleValued ) sum+= e ;

展開された場合:

element= data.get(130) ;
int sum= 0 ;
sum+= element.monday ;
sum+= element.tuesday ;
sum+= element.wednesday ;
sum+= element.thursday ;
sum+= element.friday ;

この場合、要素が 5 つしかないため、違いはほとんどありません。最初の方法は物事を少し短くし、2 番目の方法はより明確にします。個人的に、私は明快さのために投票します。ここで、5 項目ではなく 1,000 項目、または 20 項目であった場合、2 番目のケースの繰り返しは多すぎて、最初のケースが優先されます。これについても、別の一般的なルールがあります。すべての要素に個別に名前を付けることができる場合は、正確にそうする方がよいでしょう。要素に名前を付けようとしているときに、数字またはアルファベットの連続した文字を使用していることに気付いた場合 (月の日のように自然に、または物事が異なる名前を持っていないように見えるため)、それは配列です。これら 2 つの基準を適用した後でも、明確でないケースが見つかる可能性があります。この場合、コインを投げて、プログラムの開発を開始し、逆にどうなるか少し考えてみてください。いつでも気が変わることができます。

あなたのアプリケーションが実際に科学的なものである場合、そのような長い (そして役に立たない) 説明を許してください。ただし、私の答えは、似たようなものを探している他の人に役立つ可能性があります。

于 2013-08-10T07:58:23.803 に答える
3

ArrayList配列プリミティブの代わりに使用します。「立方体」を割り当てるという非効率的な無駄遣いをすることなく、3 つの次元を持つことができます。


@nIcE cOw提案されたs のようなカスタム クラスを作成しない場合Collection、この種のことはプリミティブ配列よりも面倒です。これは、Java が冗長であることを好み、演算子のオーバーロード ( C++ のように) のような特定のことを行わなかったりArrayList、配列から簡単にインスタンス化する機能を提供したりしないためです。

@sbat例として、ArrayLists を使用したheresの例を示します。

public static <T> ArrayList<T> toAL(T ... input) {
    ArrayList<T> output = new ArrayList<T>();
    for (T item : input) {
        output.add(item);
    }
    return output;
}

public static void main(String[] args) {
    ArrayList<ArrayList<ArrayList<Integer>>> a = toAL(
        toAL(
            toAL(0, 1, 2)
        ),
        toAL(
            toAL(4, 5)
        ),
        toAL(
            toAL(6)
        )
    );
    System.out.println(a.get(0).get(0).get(2));
    System.out.println(a.get(1).get(0).get(1));
    System.out.println(a.get(2).get(0).get(0));
}
于 2013-08-10T05:49:59.307 に答える
2

もちろん、次のようにしても構文的に問題はありません。

int[][][] a = {{{0, 1, 2}}, {{4, 5}}, {{6}}};
System.out.println(a[0][0].length); // 3
System.out.println(a[1][0].length); // 2
System.out.println(a[2][0].length); // 1

実際、それが Java の多次元配列であり、配列内の配列です。これに関する唯一の問題は、後で混乱したり維持するのが難しくなったりする可能性があることですが、ArrayLists 内で ArrayLists を使用する場合も同様です。

List<List<List<Integer>>> list = ...;
System.out.println(list.get(0).get(1).get(50)); // using ArrayList

ただし、コレクションよりも配列を好む理由については、まだいくつかの理由があります。ただし、状況によっては、ArrayLists またはその他のコレクションの方が望ましい場合があります。

于 2013-08-10T06:02:17.357 に答える