teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

バグ修正ついでに説明追加

2021/10/10 18:26

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -8,7 +8,28 @@
8
8
  ----
9
9
 
10
10
  Sample クラスを活用するようにしてみました。
11
+ 科目の表示順・追加等は Sample のコンストラクタで行ってください。
12
+ ex) ```Sample sample = new Sample("名前","国語","外国語","数学");```
11
13
 
14
+ 同一名のデータは、纏めます。
15
+ ex)
16
+ ```plain
17
+ 田中ゆうき,国語,80
18
+ 佐藤かつひこ,数学,50
19
+ 田中ゆうき,数学,30
20
+ 田中たくや,国語,60
21
+ ```
22
+ ```plain
23
+ | 名前 |国語|外国語|数学|
24
+ +-----------------------------+
25
+ |田中ゆうき | 80| | 30|
26
+ +-----------------------------+
27
+ |佐藤かつひこ| | | 50|
28
+ +-----------------------------+
29
+ |田中たくや | 60| | |
30
+ +-----------------------------+
31
+ ```
32
+
12
33
  ```java
13
34
  package teratail_java.q363724;
14
35
 
@@ -19,7 +40,7 @@
19
40
 
20
41
  public class Sample {
21
42
  public static void main(String[] args) throws IOException {
22
- Sample sample = new Sample("名前","国語","数学");
43
+ Sample sample = new Sample("名前","国語","外国語","数学");
23
44
  File file = new File("Sample1.txt");
24
45
  try(BufferedReader br = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8); ) {
25
46
  for(String line; (line=br.readLine()) != null; ) {
@@ -119,7 +140,7 @@
119
140
  StringJoiner sj = new StringJoiner("|","|","|");
120
141
  for(int i=0; i<maxWidth.length; i++) {
121
142
  if(i == nameIndex) {
122
- sj.add(String.format("%-"+maxWidth[i]+"s", s.name)); //名前=左詰め
143
+ sj.add(s.name + " ".repeat(maxWidth[i]-count(s.name))); //名前=左詰め
123
144
  } else if(s.hasScore(headerList.get(i))) {
124
145
  sj.add(String.format("%"+maxWidth[i]+"d", s.getScore(headerList.get(i)))); //得点=右詰め
125
146
  } else {

2

コード追加

2021/10/10 18:26

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -8,8 +8,6 @@
8
8
  ----
9
9
 
10
10
  Sample クラスを活用するようにしてみました。
11
- コンストラクタに渡す科目の位置に合わせて点数が表示されます。
12
- 国語と数学の間に外国語とか入れても大丈夫ですし、"田中ゆうき,数学,30" という行を追加すれば田中ゆうきさんの行に国語と数学の点数が並びます。
13
11
 
14
12
  ```java
15
13
  package teratail_java.q363724;

1

コード追加

2021/10/10 18:07

投稿

jimbe
jimbe

スコア13355

answer CHANGED
@@ -3,4 +3,141 @@
3
3
  読んだ時に編集する場合は、 lineList.add(line.split(",")); で直接 lineList に入れているのを変えて、必要な構造で add するようにします。
4
4
 
5
5
  表示する時に変数する場合は、 writeLine の //2列目以降を右寄せ の中での k のループの時点で、line[j] を出力するか空白を出力するかを判断するようにします。
6
- が、List をわざわざ 2次元配列にしているなどの構造から見て、読み込み時に変換したほうが良いと思います。
6
+ が、List をわざわざ 2次元配列にしているなどの構造から見て、読み込み時に変換したほうが良いと思います。
7
+
8
+ ----
9
+
10
+ Sample クラスを活用するようにしてみました。
11
+ コンストラクタに渡す科目の位置に合わせて点数が表示されます。
12
+ 国語と数学の間に外国語とか入れても大丈夫ですし、"田中ゆうき,数学,30" という行を追加すれば田中ゆうきさんの行に国語と数学の点数が並びます。
13
+
14
+ ```java
15
+ package teratail_java.q363724;
16
+
17
+ import java.io.*;
18
+ import java.nio.charset.StandardCharsets;
19
+ import java.nio.file.Files;
20
+ import java.util.*;
21
+
22
+ public class Sample {
23
+ public static void main(String[] args) throws IOException {
24
+ Sample sample = new Sample("名前","国語","数学");
25
+ File file = new File("Sample1.txt");
26
+ try(BufferedReader br = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8); ) {
27
+ for(String line; (line=br.readLine()) != null; ) {
28
+ String[] array = line.split(",");
29
+ sample.put(array[0], array[1], Integer.parseInt(array[2]));
30
+ }
31
+ sample.drawSheet();
32
+ } catch (IOException e) {
33
+ e.printStackTrace();
34
+ }
35
+ }
36
+
37
+ private List<String> headerList;
38
+ private int nameIndex;
39
+ private int[] maxWidth;
40
+ private Map<String,Student> studentMap = new HashMap<>();
41
+
42
+ private static class Student {
43
+ final int number;
44
+ final String name;
45
+ private final Map<String,Integer> scoreMap = new HashMap<>();
46
+ Student(int number, String name) {
47
+ this.number = number;
48
+ this.name = name;
49
+ }
50
+ void putScore(String subject, int score) {
51
+ scoreMap.put(subject, score);
52
+ }
53
+ boolean hasScore(String subject) {
54
+ return scoreMap.containsKey(subject);
55
+ }
56
+ int getScore(String subject) {
57
+ return scoreMap.get(subject);
58
+ }
59
+ }
60
+
61
+ Sample(String... header) {
62
+ headerList = Arrays.asList(header);
63
+
64
+ nameIndex = headerList.indexOf("名前");
65
+ if(nameIndex < 0) throw new IllegalArgumentException("'名前' がありません");
66
+
67
+ maxWidth = new int[headerList.size()];
68
+ for(int i=0; i<headerList.size(); i++) {
69
+ maxWidth[i] = count(headerList.get(i));
70
+ }
71
+ }
72
+
73
+ void put(String name, String subject, int score) {
74
+ Student s = studentMap.get(name);
75
+ if(s == null) {
76
+ s = new Student(studentMap.size()+1, name); //number は出現順にしておく
77
+ studentMap.put(name, s);
78
+ maxWidth[nameIndex] = Math.max(maxWidth[nameIndex], count(s.name));
79
+ }
80
+ s.putScore(subject, score);
81
+ int i = headerList.indexOf(subject);
82
+ if(i >= 0 && i != nameIndex) maxWidth[i] = Math.max(maxWidth[i], count(""+score));
83
+ }
84
+
85
+ void drawSheet() {
86
+ drawHeader();
87
+ drawRowSeparator();
88
+ studentMap.values().stream()
89
+ .sorted(Comparator.comparingInt(s -> s.number)) //number順に並び替え
90
+ .forEach(s -> { drawStudent(s); drawRowSeparator(); });
91
+ }
92
+
93
+ private void drawHeader() {
94
+ StringJoiner sj = new StringJoiner("|","|","|");
95
+ for(int i=0; i<headerList.size(); i++) {
96
+ sj.add(getCenteringString(headerList.get(i), maxWidth[i]));
97
+ }
98
+ System.out.println(sj.toString());
99
+ }
100
+
101
+ private String getCenteringString(String str, int width) {
102
+ int space = width - count(str);
103
+ int pre = space / 2;
104
+ int post = space - pre;
105
+ return " ".repeat(pre)+str+" ".repeat(post);
106
+ }
107
+
108
+ private String rowSeparator;
109
+ private void drawRowSeparator() {
110
+ if(rowSeparator == null) {
111
+ StringJoiner sj = new StringJoiner("-","+","+");
112
+ for(int i=0; i<maxWidth.length; i++) {
113
+ sj.add("-".repeat(maxWidth[i]));
114
+ }
115
+ rowSeparator = sj.toString();
116
+ }
117
+ System.out.println(rowSeparator);
118
+ }
119
+
120
+ private void drawStudent(Student s) {
121
+ StringJoiner sj = new StringJoiner("|","|","|");
122
+ for(int i=0; i<maxWidth.length; i++) {
123
+ if(i == nameIndex) {
124
+ sj.add(String.format("%-"+maxWidth[i]+"s", s.name)); //名前=左詰め
125
+ } else if(s.hasScore(headerList.get(i))) {
126
+ sj.add(String.format("%"+maxWidth[i]+"d", s.getScore(headerList.get(i)))); //得点=右詰め
127
+ } else {
128
+ sj.add(" ".repeat(maxWidth[i]));
129
+ }
130
+ }
131
+ System.out.println(sj.toString());
132
+ }
133
+
134
+ //英数字、カタカナ、ひらがな、漢字の文字コードを分類する
135
+ public static int count(String str) {
136
+ int count = 0;
137
+ for(char c : str.toCharArray()) {
138
+ count += Character.UnicodeBlock.of(c) == Character.UnicodeBlock.BASIC_LATIN ? 1 : 2;
139
+ }
140
+ return count;
141
+ }
142
+ }
143
+ ```