前提・実現したいこと
テキストファイルの情報を読み込みそれを基に、表を作成。
・テキストファイル
田中ゆうき,国語,80
佐藤かつひこ,数学,50
発生している問題・エラーメッセージ
エラーメッセージ
該当のソースコード
java
1class Sample { 2 3 4 5 public static void main(String[] args)throws IOException { 6 7 File file = new File("Sample1.txt"); 8 ArrayList<String[]> lineList = new ArrayList<>(); 9 String az= "名前,国語,数学"; 10 lineList.add(az.split(",")); 11 12 try(BufferedReader br= Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)){ 13 String line; 14 while ((line = br.readLine()) != null) { 15 lineList.add(line.split(",")); 16 } 17 } catch (IOException e) { 18 e.printStackTrace(); 19 } 20 21 String[][] data = lineList.toArray(new String[lineList.size()][]); 22 23 24 } 25 26 27 28}
試したこと
ここに問題に対して試したことを記載してください。
補足情報(FW/ツールのバージョンなど)
ここにより詳細な情報を記載してください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/10 07:24
2021/10/10 07:41
2021/10/10 07:48
2021/10/10 08:12
2021/10/10 08:14
2021/10/10 08:21
2021/10/10 08:22
2021/10/10 08:42
回答3件
0
点数のみを該当セルに入れる方法は主に二つ、データを読んだ時に編集するか、表示する時に編集するか、です。
読んだ時に編集する場合は、 lineList.add(line.split(",")); で直接 lineList に入れているのを変えて、必要な構造で add するようにします。
表示する時に変数する場合は、 writeLine の //2列目以降を右寄せ の中での k のループの時点で、line[j] を出力するか空白を出力するかを判断するようにします。
が、List をわざわざ 2次元配列にしているなどの構造から見て、読み込み時に変換したほうが良いと思います。
Sample クラスを活用するようにしてみました。
科目の表示順・追加等は Sample のコンストラクタで行ってください。
ex) Sample sample = new Sample("名前","国語","外国語","数学");
同一名のデータは、纏めます。
ex)
plain
1田中ゆうき,国語,80 2佐藤かつひこ,数学,50 3田中ゆうき,数学,30 4田中たくや,国語,60
plain
1| 名前 |国語|外国語|数学| 2+-----------------------------+ 3|田中ゆうき | 80| | 30| 4+-----------------------------+ 5|佐藤かつひこ| | | 50| 6+-----------------------------+ 7|田中たくや | 60| | | 8+-----------------------------+
java
1package teratail_java.q363724; 2 3import java.io.*; 4import java.nio.charset.StandardCharsets; 5import java.nio.file.Files; 6import java.util.*; 7 8public class Sample { 9 public static void main(String[] args) throws IOException { 10 Sample sample = new Sample("名前","国語","外国語","数学"); 11 File file = new File("Sample1.txt"); 12 try(BufferedReader br = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8); ) { 13 for(String line; (line=br.readLine()) != null; ) { 14 String[] array = line.split(","); 15 sample.put(array[0], array[1], Integer.parseInt(array[2])); 16 } 17 sample.drawSheet(); 18 } catch (IOException e) { 19 e.printStackTrace(); 20 } 21 } 22 23 private List<String> headerList; 24 private int nameIndex; 25 private int[] maxWidth; 26 private Map<String,Student> studentMap = new HashMap<>(); 27 28 private static class Student { 29 final int number; 30 final String name; 31 private final Map<String,Integer> scoreMap = new HashMap<>(); 32 Student(int number, String name) { 33 this.number = number; 34 this.name = name; 35 } 36 void putScore(String subject, int score) { 37 scoreMap.put(subject, score); 38 } 39 boolean hasScore(String subject) { 40 return scoreMap.containsKey(subject); 41 } 42 int getScore(String subject) { 43 return scoreMap.get(subject); 44 } 45 } 46 47 Sample(String... header) { 48 headerList = Arrays.asList(header); 49 50 nameIndex = headerList.indexOf("名前"); 51 if(nameIndex < 0) throw new IllegalArgumentException("'名前' がありません"); 52 53 maxWidth = new int[headerList.size()]; 54 for(int i=0; i<headerList.size(); i++) { 55 maxWidth[i] = count(headerList.get(i)); 56 } 57 } 58 59 void put(String name, String subject, int score) { 60 Student s = studentMap.get(name); 61 if(s == null) { 62 s = new Student(studentMap.size()+1, name); //number は出現順にしておく 63 studentMap.put(name, s); 64 maxWidth[nameIndex] = Math.max(maxWidth[nameIndex], count(s.name)); 65 } 66 s.putScore(subject, score); 67 int i = headerList.indexOf(subject); 68 if(i >= 0 && i != nameIndex) maxWidth[i] = Math.max(maxWidth[i], count(""+score)); 69 } 70 71 void drawSheet() { 72 drawHeader(); 73 drawRowSeparator(); 74 studentMap.values().stream() 75 .sorted(Comparator.comparingInt(s -> s.number)) //number順に並び替え 76 .forEach(s -> { drawStudent(s); drawRowSeparator(); }); 77 } 78 79 private void drawHeader() { 80 StringJoiner sj = new StringJoiner("|","|","|"); 81 for(int i=0; i<headerList.size(); i++) { 82 sj.add(getCenteringString(headerList.get(i), maxWidth[i])); 83 } 84 System.out.println(sj.toString()); 85 } 86 87 private String getCenteringString(String str, int width) { 88 int space = width - count(str); 89 int pre = space / 2; 90 int post = space - pre; 91 return " ".repeat(pre)+str+" ".repeat(post); 92 } 93 94 private String rowSeparator; 95 private void drawRowSeparator() { 96 if(rowSeparator == null) { 97 StringJoiner sj = new StringJoiner("-","+","+"); 98 for(int i=0; i<maxWidth.length; i++) { 99 sj.add("-".repeat(maxWidth[i])); 100 } 101 rowSeparator = sj.toString(); 102 } 103 System.out.println(rowSeparator); 104 } 105 106 private void drawStudent(Student s) { 107 StringJoiner sj = new StringJoiner("|","|","|"); 108 for(int i=0; i<maxWidth.length; i++) { 109 if(i == nameIndex) { 110 sj.add(s.name + " ".repeat(maxWidth[i]-count(s.name))); //名前=左詰め 111 } else if(s.hasScore(headerList.get(i))) { 112 sj.add(String.format("%"+maxWidth[i]+"d", s.getScore(headerList.get(i)))); //得点=右詰め 113 } else { 114 sj.add(" ".repeat(maxWidth[i])); 115 } 116 } 117 System.out.println(sj.toString()); 118 } 119 120 //英数字、カタカナ、ひらがな、漢字の文字コードを分類する 121 public static int count(String str) { 122 int count = 0; 123 for(char c : str.toCharArray()) { 124 count += Character.UnicodeBlock.of(c) == Character.UnicodeBlock.BASIC_LATIN ? 1 : 2; 125 } 126 return count; 127 } 128}
投稿2021/10/10 08:46
編集2021/10/10 18:26総合スコア13209
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/10 09:02
2021/10/10 09:59
2021/10/10 12:14
0
タイトルの「ハイフンを連続して表示させたい」についての回答です。
次のコードのどこにあるか見つけてください。
Java
1import java.util.ArrayList; 2import java.io.*; // IOExcepton, File, BufferedReader 3import java.nio.file.Files; 4import java.nio.charset.StandardCharsets; 5 6class Sample { 7 public static void main(String[] args) throws IOException { 8 File file = new File("Sample1.txt"); 9 ArrayList<String[]> lineList = new ArrayList<>(); 10 lineList.add("名前,国語,数学".split(",")); 11 int[] width = { 4, 4, 4 }; 12 String line; 13 try (BufferedReader br = Files.newBufferedReader(file.toPath(), 14 StandardCharsets.UTF_8)) { 15 while ((line = br.readLine()) != null) { 16 String[] s = line.split(","); 17 String[] t = { s[0], "", "" }; 18 if (s[1].equals("国語")) t[1] = s[2]; 19 if (s[1].equals("数学")) t[2] = s[2]; 20 for (int n, i = 0; i < 3; i++) 21 if ((n = count(t[i])) > width[i]) width[i] = n; 22 lineList.add(t); 23 } 24 } catch (IOException e) { 25 e.printStackTrace(); 26 return; 27 } 28 line = "+" + "-".repeat(width[0] + width[1] + width[2] + 2) + "+"; 29 drawHeader(lineList, width, line); 30 drawTable(lineList, width, line); 31 } 32 33 public static void drawHeader(ArrayList<String[]> a, int[] width, String line) { 34 String[] s = a.get(0); 35 System.out.println(line); 36 for (int i = 0; i < 3; i++) { 37 int w = count(s[i]); 38 int j = (width[i] - w) / 2, k = width[i] - j - w; 39 System.out.print("|" + " ".repeat(j) + s[i] + " ".repeat(k)); 40 } 41 System.out.println("|"); 42 System.out.println(line); 43 } 44 45 public static void drawTable(ArrayList<String[]> a, int[] width, String line) { 46 for (int i = 1; i < a.size(); i++) { 47 String[] s = a.get(i); 48 System.out.print("|" + s[0] + " ".repeat(width[0] - count(s[0]))); 49 System.out.print("|" + " ".repeat(width[1] - count(s[1])) + s[1]); 50 System.out.print("|" + " ".repeat(width[2] - count(s[2])) + s[2]); 51 System.out.println("|"); 52 System.out.println(line); 53 } 54 } 55 56 public static int count(String str) { 57 int count = 0; 58 for (int i = 0; i < str.length(); i++) { 59 var b = Character.UnicodeBlock.of(str.charAt(i)); 60 if (b.equals(Character.UnicodeBlock.BASIC_LATIN)) 61 count++; 62 else if (b.equals(Character.UnicodeBlock.KATAKANA) || 63 b.equals(Character.UnicodeBlock.HIRAGANA) || 64 b.equals(Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS)) 65 count += 2; 66 } 67 return count; 68 } 69}
投稿2021/10/10 14:23
総合スコア8224
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/10/10 14:50
2021/10/10 16:23
2021/10/10 16:33
2021/10/10 16:40
2021/10/10 16:46
0
ベストアンサー
まず気になったのは『例外処理』関係。
try(BufferedReader br= Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)){ String line; while ((line = br.readLine()) != null) { lineList.add(line.split(",")); } } catch (IOException e) { e.printStackTrace(); } String[][] data = lineList.toArray(new String[lineList.size()][]);
確かに動きはしますが、『なんのための例外処理』なのでしょうか。
例外処理は『ファイルが無かった場合』とかのように例外的な、『想定されていない』場合を対処するためのはずです。
でも上記コードだと、『ファイルが無い場合でも、リストを配列に変換する』とかの処理をしてしまいます。
ただし、今回の問題はここじゃないので中断します。
次に、質問にあるコードは絶対にダメだとは言いませんが、あまり良い傾向ではありませんね。
(別に悪く言うつもりはまったくありません)
参考1: なぜ読みやすいコードが必要なのか - コードの可読性を高める手法をサンプルで学ぶ
参考2: 良いコードとは slideshare
参考3: 他の人のコードが読みづらい理由でのmrasuさんのご回答
参考3でのmrasuさんのご回答で、
コードが読める人向け
コードが何をしたいかわからない。
直観に反した(「自分だったらこう書く」という物と違う)動きをしていて、動きが把握しづらい
データ変更と描画が同時に行われているなど、多数の状況を把握し続ける必要がある
というのがあるかなと思います。
と書かれています。これが私が初見で思ったことですねぇ。
ダメとは言いませんが、今回の場合、もっとシンプルに書けるはずです。
完璧なロジックはまだ思い浮かんでいませんが、ざっくりとしたロジックが思い浮かんでいます。(私の中で)
プログラミングっていうのは、出鱈目に書けばいいってものではありません。
プログラミングは現実世界のシミュレーションです。
なのでとりあず、プログラミングがとかは置いといて、現実世界で考えてみましょう。
田中ゆうき,国語,80 佐藤かつひこ,数学,50
というのを、
| 名前 |国語|数学| +----------------------+ |田中ゆうき | 80| | +----------------------+ |佐藤かつひこ| | 50| +----------------------+
の状態にするにはどうしますか? (なんかズレがあるようなのでこちらで適当に修正しています。違う所があるなら読みかえてください)
私なら、
1. 何を書くかを考える( 国語の方に書くのか、数学の方に書くのかとか ) 2. それぞれのセル(?)の長さはどういう風にするか(長さの基準等) 3. 文字はどのように並んでいるか(右揃え? 左揃え? センタリング? ) 4. 数字(国語の点数等)はどのように並んでいるか(〃) 5. 区切り線(?)の"+----+"のやつの長さはどうするか 6. 区切り線(?)の"|"はどのように入れるか(位置とか)
をそれぞれ考える。
つまり、規則性を見付けるのです。
何を書くか(= 1)は元のデータ "田中ゆうき,国語,80" とかの二番目から考える。
それぞれのセル云々(= 2) は『その列の最大行数から考える』。
文字や数字はどのように並んでいるか(= 3, 4)は『項目名は中央揃え、名前は左揃え、点数は右寄せ』。
"+---+" の長さ(= 5) は『レコード(*1)の長さ分』。
*1: ここでいうレコードは、一行分のデータ列(ただし"|"等も含めている)
6は2と一緒ですね。
次に実際にノートかホワイトボードかなんかに上記の表を書いてみましょう。
[Flow]: 1. Excelでいう列のそれぞれの最大行数を求める 2. (1)のそれぞれの長さを『最大値』として"名前"や"国語"等が中心に来るように書く 3. 以下を『書くものが無くなるまで』繰り返す 3.1. (2)で出来た行の最大の長さ分、"+---+" 的なものを書く 3.2. (2)と同様に『名前を左揃え』、『数字を右揃え』で書く 4. (3.1)と同様に線を引く
みたいな流れになるはずです。(まあ、実際には(3.1)と(3.2)が逆になるかもしれないが )
後はこれを実装すればいいだけです。
まだわかりにくい部分があれば、同じように流れを考える。
で、(3.1)での"+---+" のやつは、どの行?でも同じ長さですね。完全固定。
なので、一度定義すれば単に描画すればいいだけです。
と考えると、
[Flow] 1. 列のそれぞれの最大行数を計算する 2. ヘッダに相当する、"名前"等の部分を(1)を最大数としてセンタリングして表示 3. (2)の長さ分、"+---+"のような文字列を生成 4. 以下を『書くものが無くなるまで』繰り返す 4.1. (3)で生成した文字列を表示 4.2. (2)の要領で『左揃え』や『右揃え』で表示していく 5. (3)で生成した文字列を表示
のような感じになりますね。(順番が変わる可能性があるが)
[コメントにて]
1番の何を書くかを考えるについてですが、...
あ、それでもいいですよ。
とりあえず、一気に作るのではなく、少しづつ作っていってください。
自分の考えが正しいかどうかもそれでわかります。
投稿2021/10/10 08:23
編集2021/10/10 08:59総合スコア4962
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。