質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

2回答

6496閲覧

valueが2次元配列のHashMapでvalueの2次元目を参照したい

mobage_sb69er

総合スコア7

多次元配列

1次元配列内にさらに配列を格納している配列を、多次元配列と呼びます。

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

0クリップ

投稿2020/01/29 11:43

編集2020/01/30 09:37

HashMap<String, String[][]> map = new HashMap<>();
のようなvalueが(String型)2次元配列のHashMapを使っているのですが、Iteratorを用いて

Iterator<String> key_itr = map.keySet().iterator(); while(key_itr.hasNext()) { String str_key = (String)key_itr.next(); for(int i=0;i<len_zwei(map.get(str_key));i++) { // ここまでOK for(int j=0;j<len_eins((map.get(str_key))[i]);j++) { // この前の行でエラー } } }

のようにIteratorでmapのkeyを順に取り出してそのvalueの配列でfor文を回そうとしています。しかし、2つ目のfor文でlen_eins()というメソッドを用いてstr_keyのvalueにある2次元配列のi番目の配列の長さ(要素の数)を出しているところで java.lang.ArrayIndexOutOfBoundsExceptionのエラーが発生してしまいます。エラーが出ないようにするにはどうしたらいいでしょうか。

len_eins,len_zweiメソッドは次のような感じです。

len

1 public static int len_eins(String[] str) { 2 int i = 0; 3 while(str[i] != null) { 4 i++; 5 } 6 return i; 7 } 8 9 public static int len_zwei(String[][] str) { 10 int i = 0; 11 while(str[i][0] != null) { 12 i++; 13 } 14 return i; 15 }

HashMapに入っていない普通の2次元配列(str[][])でlen_eins(str[0])のようにした場合はエラーは出ず、正しい配列に入っている(nullでない)要素数をが返ります。HashMapには予めkeyとvalueが入っており、str_keyもmap.get(str_key)[][]の中身も出力はできます。

追記のプログラム

Iterator<Map.Entry<String, String[][]>> entry_itr1 = map.entrySet().iterator(); while(entry_itr1.hasNext()) { Map.Entry<String, String[][]> entry1 = entry_itr1.next(); for(int i=0;i<len_zwei(entry1.getValue());i++) { for(int j=0;j<len_eins(entry1.getValue()[i]);j++) { // 1度目の処理 } } } Iterator<Map.Entry<String, String[][]>> entry_itr2 = map.entrySet().iterator(); while(entry_itr2.hasNext()) { // この次の行でエラー発生 Map.Entry<String, String[][]> entry2 = entry_itr2.next(); // 380行目 String str_key2 = entry2.getKey(); for(int i=0;i<len_zwei(entry2.getValue());i++) { for(int j=0;j<len_eins(entry2.getValue()[i]);j++) { // 2度目の処理 } } }

追記のエラー文

Exception in thread "main" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445) at java.util.HashMap$EntryIterator.next(HashMap.java:1479) at java.util.HashMap$EntryIterator.next(HashMap.java:1477) at KCFG.KCFG_main.ToDCG(main.java:380) at KCFG.KCFG_main.main(main.java:109)

main文内の109行目で上の追記のプログラムのあるメソッドを呼び出しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2020/01/29 12:21 編集

ばらばらのコードでは無く, 実行・再現できる状態のコードをご提示願えますか. でなければ, 再現しようと追加したデータ・コードによって再現できない可能性があります. また, 例外もコード同様の記法で全文をご提示ください.
guest

回答2

0

ベストアンサー

とりあえずkeySetで持ってきてキーでマップから持ってくるというのが無駄なので、
entrySetで持ってきましょう。

java

1Iterator<Map.Entry<String, String[][]>> entry_itr = map.entrySet().iterator(); 2 while(entry_itr.hasNext()) { 3 Map.Entry<String, String[][]> entry = entry_itr.next(); 4 for(int i=0;i<len_zwei(entry.getValue());i++) { 5 // ここまでOK 6 for(int j=0;j<len_eins(entry.getValue()[i]);j++) { 7 // この前の行でエラー 8 } 9 } 10 }

追記:改めてみると長さを取得するより、nullを見つけたら脱出でいいのでは?

java

1Iterator<Map.Entry<String, String[][]>> entry_itr = map.entrySet().iterator(); 2 while(entry_itr.hasNext()) { 3 Map.Entry<String, String[][]> entry = entry_itr.next(); 4 String[][] value = entry.getValue(); 5 for(int i=0; i<value.length ;i++) { 6 String[] row = value[i]; 7 if(row[0] == null) break; 8 for(int j=0;j<row.length;j++) { 9 if(row[j] == null) break; 10 } 11 } 12 }

で、問題ですが、このlen関係のメソッドは最初にnullに行き当たるまでの要素数をカウントすることになりますが、nullがない場合も止まらず探し続けるため、当然範囲外に出てしまいます。

java

1 public static int len_eins(String[] str) { 2 int i = 0; 3 while(str[i] != null) { // nullがない場合は無限ループ 4 i++; 5 } 6 return i; 7 }

配列の最大要素数で抑えるか、拡張forで処理するかになります。

java

1 public static int len_eins(String[] str) { 2 int i = 0; 3 for (String s : str) { 4 if (s == null) { 5 return i; 6 } 7 i++; 8 } 9 return i; 10 }

また今の構造だと、ループのたびにこれを呼び出すことになってしまうので、
ループに入る前に計算して、使いまわしましょう。

投稿2020/01/29 19:47

編集2020/01/31 18:23
swordone

総合スコア20651

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mobage_sb69er

2020/01/30 08:53

拡張for文を用いることで動くようになりました。ありがとうございます。 ただ、元々追記のプログラムのようにIteratorで2周するようにしていて、swordoneさんの回答で1周目はうまく動くのですが、2周目はMap.Entry<>の宣言でエラーが出てしまいます。同じmapを2周はできないものなのでしょうか?それともやり方が悪いのでしょうか?
swordone

2020/01/30 09:26

どういうエラーが出ているのですか?すべてを質問に追記してください。
swordone

2020/01/30 16:35

これ、2週目の話じゃないですね、おそらく。 ループ処理中にmap触ってないですか?map.remove(何か)とか。
mobage_sb69er

2020/01/30 17:32 編集

覚えてる限りだとループ内の最後でmap.remove()を使ってますね。一度remove()で消去して同じkeyで違うvalueをput()してvalueを書き換えているのですが、これだと別の方法を取った方がいいんですかね?もしかして、map内のvalueの書き換えはremeve()する必要なかったりします?
swordone

2020/01/30 18:05

Iteratorでループしている最中に、Iteratorのメソッド以外の方法で元のコレクション(今回の場合Map)を変更してはいけません。この例外ConcurrentModificationExceptionは、そうした場合に発生します。 Map.EntryのメソッドにsetValueがあります。これを使うことでキーに対応する値を差し替えることができます。 またMap一般の話として、すでに登録されているキーで再度putした場合、上書きされるため、わざわざremoveしてputしなおすという操作は必要ありません。
mobage_sb69er

2020/01/31 07:11

思った通りに動くようになりました。ありがとうございます! map自体触ったのが初めてなので知りませんでしたが、put()で上書きできるんですね。勉強になりました。
guest

0

piaza.io で以下のコードを実行しても例外は発生しませんでした.

java

1import java.util.*; 2 3public class Main { 4 public static void main(String[] args) throws Exception { 5 HashMap<String, String[][]> map = new HashMap<>(); 6 7 map.put("A", new String[][]{{"a1","a2","a3",null},{"aa1","aa2",null},{null}}); 8 map.put("B", new String[][]{{"b1",null},{"bb1","bb2","bb3","bb4",null},{null}}); 9 10 Iterator<String> key_itr = map.keySet().iterator(); 11 while(key_itr.hasNext()) { 12 String str_key = (String)key_itr.next(); 13 for(int i=0;i<len_zwei(map.get(str_key));i++) { 14 // ここまでOK 15 for(int j=0;j<len_eins((map.get(str_key)[i]));j++) { 16 // この前の行でエラー 17 System.out.println(map.get(str_key)[i][j]); 18 } 19 } 20 } 21 } 22 public static int len_eins(String[] str) { 23 int i = 0; 24 while(str[i] != null) { 25 i++; 26 } 27 return i; 28 } 29 public static int len_zwei(String[][] str) { 30 int i = 0; 31 while(str[i][0] != null) { 32 i++; 33 } 34 return i; 35 } 36}

plain

1a1 2a2 3a3 4aa1 5aa2 6b1 7bb1 8bb2 9bb3 10bb4

投稿2020/01/29 12:30

編集2020/01/29 12:34
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

mobage_sb69er

2020/01/29 12:54

手元にエラーの出たプログラムが無かったのでjimbeさんのと似たようなプログラムを作成しましたがエラーは出ませんでした。 エラーの出たプログラムは クラス内でmapを定義、初期化→main内でそのクラスをオブジェクト化→mapをメソッドに引き渡してメソッド内で文字列が格納された2次元配列をkeyと共にmapに追加→再度別のメソッドにmapを引き渡してそのメソッド内でIteratorとfor文を用いて値の表示 のような手順をたどってエラーが発生していました。
jimbe

2020/01/29 13:01

「質問への追記・修正依頼」にも書きましたが, 再現できるコードをご提示して頂かなくては, いくら言葉で説明されても mobage_sb69er さんが遭遇した事象と同じ状態には出来ません. なんとか思い出して頂いて再現したコードをご提示頂くか, 「エラーの出たプログラム」を持ってきて頂く必要があるかと思います.
mobage_sb69er

2020/01/29 13:19

すいません。そうですよね。 明日エラーの出たプログラムを再度見直して、自分で解決できなさそうならそのプログラムを追記しようと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問