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

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

ただいまの
回答率

89.53%

実現方法を教えてください。

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 1,157

lena

score 28

java初心者です。
入力ファイルをもとに計算Cと判定マスタMを使用して入力ファイルの値をoutA.csv、outB.csvに
出力したいのですが、想定とおりに実装できません。

【問題点】
①出力結果が2回づつ表示されています。
②inM.csvファイルが空の場合エラー表示して通常終了したい
のですが次の処理に進んでしまいます。

以上2点の解決方法をお教えいただけないでしょうか。

【仕様内容】
入力ファイルの数値をキーとして計算Cを読込みます。
読込んだ計算Cの値で入力ファイルの数値を除算します。

除算した結果が偶数の場合、判定Mの「002」を読込みます。
判定Mの値が「○」の場合、outAに入力ファイルの値を出力し、
「×」の場合は、outBに入力ファイルの値を出力します。

除算した結果が奇数の場合、判定Mの「001」を読込みます。
判定Mの値が「○」の場合、outAに入力ファイルの値を出力し、
「×」の場合は、outBに入力ファイルの値を出力します。

入力file        計算C        判定M
                                   キー 値
 10             キー 値      奇数   0019               1,2        偶数   002,○
 8               2,3
 7               3,1
 6               4,2
 5               5,3
 4               6,1
 3               7,2
 2               8,3
 1               9,1
                10,2

【実現したい出力例】
outA.csv   outB.csv
6             10
4              9
               8
               7
               5
               3
               2
               1
package test5;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;

public class JudgementValue {

    public static void main(String[] args) {

        BufferedReader brA = null; //inA Inputファイル入力用
        BufferedReader brC = null; //inC 計算ファイル入力用
        BufferedReader brM = null; //inM 判定マスタファイル入力用
        BufferedWriter bwA = null ; //outAファイル出力用
        BufferedWriter bwB = null ; //outBファイル出力用
        String stA = ""; //inAファイルデータを格納
        String stC = ""; //inCファイルデータを格納
        String stM = ""; //inMファイルデータを格納
        ArrayList<String[]> alMaster = new ArrayList<String[]>(); //判定マスタ
        ArrayList<String[]> alCalc = new ArrayList<String[]>(); //計算C
        String[][] masterM = null ; //判定マスタ用
        String[][] numC = null ; //計算C用
        double quotient = 0; //除算の商い結果
        boolean emptyflgM = true; //inM判定マスタファイル空判定フラグ
        boolean emptyflgC = true; //inC計算Cファイル空判定フラグ
        boolean emptyflgA= true;  //inA入力ファイル空判定フラグ

        try{
                brC = new BufferedReader(new InputStreamReader(new FileInputStream("C:/Users/temp/Desktop/inC.csv"),"JISAutoDetect"));

        }catch(FileNotFoundException e){
            System.err.println("inC.csvファイルが見つかりません。");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        try{
                brM = new BufferedReader(new InputStreamReader(new FileInputStream("C:/Users/temp/Desktop/inM.csv"),"JISAutoDetect"));

        }catch(FileNotFoundException e){
            System.err.println("inM.csvファイルが見つかりません。");
        }catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        fileError1:
        //inMファイルデータを読み込み
        try {
            while((stM = brM.readLine()) != null){

                emptyflgM = false;

                if(stM.equals("")){
                    System.err.println("データに不備があります。");
                    break fileError1;
                }
                alMaster.add(stM.split(",")); /* ArrayListへ読み込み */
            }

            if(emptyflgM){
                System.err.println("inM.csvファイルは空です。");
                break fileError1;
            }
             masterM = new String[alMaster.size()][];

             for (int i = 0; i < alMaster.size(); i++) {

                 masterM[i] = alMaster.get(i); /* ArrayListから配列へ格納 */
             }


            //inCファイルデータを読み込み
            while((stC = brC.readLine()) != null){

                emptyflgC = false;

                if(stC.equals("")){
                    System.err.println("データに不備があります。");
                    break fileError1;
                }

                alCalc.add(stC.split(",")); /* ArrayListへ読み込み */
            }

            if(emptyflgC){
                System.err.println("inC.csvファイルは空です。");
                break fileError1;
            }

             numC = new String[alCalc.size()][];

             for (int i = 0; i < alCalc.size(); i++) {

                     numC[i] = alCalc.get(i); /* ArrayListから配列へ格納 */

                    if (!isHanNum(numC[i][0]) || !isHanNum(numC[i][1])) {
                        System.err.println("数値以外のものが含まれています。");
                            break fileError1;
                    }

             }

        } catch(IOException e){
            System.err.println("エラーが発生しました。");
            e.printStackTrace();
        }finally{
            try {
                if(brM != null){
                    brM.close();
                }
                if(brC != null){
                    brC.close();
                }
            }catch (IOException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
        }//finally

            try{
                brA = new BufferedReader(new InputStreamReader(new FileInputStream("C:/Users/temp/Desktop/inA.csv"),"JISAutoDetect"));
            }catch(FileNotFoundException e){
                System.err.println("inA.csvファイルが見つかりません。");
            }catch (UnsupportedEncodingException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
            try{
                bwA = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:/Users/temp/Desktop/outA.csv"),"SJIS"));
            }catch(FileNotFoundException e){
                System.err.println("outA.csvファイルが見つかりません。");
            }catch (UnsupportedEncodingException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
            try{
                bwB = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("C:/Users/temp/Desktop/outB.csv"),"SJIS"));
            }catch(FileNotFoundException e){
                System.err.println("outB.csvファイルが見つかりません。");
            }catch (UnsupportedEncodingException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }

        fileError2:
        try{
            //inAファイルデータを読み込み
            while((stA = brA.readLine()) != null){

                emptyflgA = false;

                if(stA.equals("")){
                    System.err.println("データに不備があります。");
                    break fileError2;
                }

                if(isHanNum(stA) == false){
                    System.err.println("数値以外のものが含まれています。");
                    break fileError2;
                }

                 for (int i = 0; i < numC.length; i++) {

                     if(stA.equals(numC[i][0])){  //入力の値と計算Cのキーの値の一致確認

                         quotient= Double.valueOf(stA) / Double.valueOf(numC[i][1]);

                        if(quotient % 2 == 0){ //偶数かどうかを確認

                            if(masterM[1][1].equals("○")){

                                bwA.write(stA);
                                bwA.newLine();
                                System.out.println("1番目:" + stA);
                            }else{
                                bwB.write(stA);
                                bwB.newLine();
                                System.out.println("2番目:" + stA);
                            }

                        }else{

                            if(masterM[0][1].equals("○")){

                                bwA.write(stA);
                                bwA.newLine();
                                System.out.println("3番目:" + stA);
                            }else{
                                bwB.write(stA);
                                bwB.newLine();
                                System.out.println("4番目:" + stA);
                            }
                        }
                    }
                 } //for
                 quotient = 0; //除算の商い結果を0にリセット
            } //while

            if(emptyflgA){
                System.err.println("inA.csvファイルは空です。");
                break fileError2;
            }

        }catch(IOException e){
            System.err.println("エラーが発生しました。");
            e.printStackTrace();
        }finally{
        try {
            if(brA != null){
                brA.close();
            }
            if(bwA != null){
                bwA.close();
            }
            if(bwB != null){
                bwB.close();
            }
            }catch (IOException e) {
                // TODO 自動生成された catch ブロック
                e.printStackTrace();
            }
        }//finally


    }//main

    /**
     * 半角数値チェック
     * @param s 文字列
     * @return true 正常  false エラー
     */
    public static boolean isHanNum(String s){
        try{
            Double.parseDouble(s);
            return true;

        }catch(Exception e){
            return false;
        }

    }


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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tatsuya6502

    2016/03/18 00:31

    入力ファイル、計算C、判定M の内容ですが、表示が崩れてしまっていて、理解できません。Java プログラムの部分のように、コードブロックで囲ってみてください。また、これらの内容から、どのように outA.csv と outB.csv の値が導かれるのかという仕様について、簡単な説明をお願いします。最後に、いまどのような間違った結果が出力されるのかも書いてください。

    キャンセル

  • lena

    2016/03/18 01:03

    tatsuya6502さん、修正依頼下さりありがとうございます。
    先ほど情報の追加をさせていただきました。

    キャンセル

回答 2

checkベストアンサー

+2

情報の追加、ありがとうございました!

エラー「演算子 / は引数の型 BufferedReader, String[] で未定義です」の意味ですが、

if(stA.equals(numC[i])){
    sum = brA / numC[i];

この sum = brA / numC[i]; で、brA が BufferedReader型、numC[i] が String[]型(文字列の配列)となっており、どちらも整数型(int)でないので除算できない、です。

まず、brA は stA の間違いではないでしょうか?

また、numC は String[][]型ですので、多分、こう書きたかったのでは?

if(stA.equals(numC[i][0])){
    sum = stA / numC[i][1];

さて、このように修正しても、まだコンパイルできないと思います。なぜなら stA も numC[i][1] も String型だからです。文字列で除算はできないので、これらを int 型に変換しないといけません。これは、Integer.parseInt(stA) のようにすればできます。

あと、変数 sum ですが、この言葉には「合計」と言う意味があるので、割り算の商を格納するのには、ちょっと紛らわしい名前です。例えば、quotient としてはどうでしょうか?

プログラムの内容を詳しく見てないので、他にも間違いがあるかもしれませんが、とりあえず、いま出ているエラーについて気づいたことは、これで全部です。



2016年3月18日 質問①と②について追記

③は説明が長くなりそうなので、後で(明日?)書きます。
取り急ぎ、①と②について回答しますね。

①数値化出来るかどうかをisHanNum(String s)メソッドを使用
したいのですが、配列の要素だと型の不一致でコンパイル
出来ません。

if (isHanNum(numC[i]) == false) {

のところですが、numC[i] とすると、長さ2の String配列が返ってくるので、たしかに型の不一致となります。以下のように、String配列の各要素を一つずつチェックしてください。

if (!isHanNum(numC[i][0]) || !isHanNum(numC[i][1])) {

②除算した結果を偶数か奇数で判断したいのですが。int同士だと
小数点以下切り捨てなので、すべてが偶数になってしまいます。

たしかに小数点以下切り捨てですが、でも、偶数だけでなく、奇数になることもあります。

まず、以下のところに間違いがあることに気づきました。

if (quotient % 2 == 0) { // 偶数かどうかを確認
    if (masterM[1][0].equals("○")) {
    // ...省略...

} else {
    if (masterM[0][0].equals("○")) {

masterM の2番目のインデックスが違います。正しくは以下のようになります。

if (quotient % 2 == 0) { // 偶数かどうかを確認
    if (masterM[1][1].equals("○")) {
    // ...省略...

} else {
    if (masterM[0][1].equals("○")) {

でも、これを直して試してみたのですが、期待した答えにならないかったですねぇ。うーん、仕様か、あるいは、期待している答えのどちらかが間違っているような気がします。

ちなみに、整数の除算は小数点以下切り捨てですが、浮動小数点型(double)の除算の場合は、小数点以下四捨五入や、繰上げも選べます。以下のようなコードを追加して、結果が、outA.csv、outB.csvのどちらになるかやってみましたが、整数除算の場合と、浮動小数点除算(四捨五入)のどちらの場合でも、答えが合わないです。

for (int i = 0; i < numC.length; i++) {

    if (stA.equals(numC[i][0])) { // 入力の値と計算Cのキーの値の一致確認

        int intA = Integer.valueOf(stA);
        int intC = Integer.valueOf(numC[i][1]);
        int intQ = intA / intC;
        boolean intEven = intQ % 2 == 0;
        int intMIndex = intEven ? 1 : 0;
        String intOut = masterM[intMIndex][1].equals("○") ? "outA" : "outB";

        System.out.format("%d: int ---- A: %4d, C: %4d, Q: %4d, even(%d): %s ==> %s%n",
                i, intA, intC, intQ, intQ, intEven, intOut);

        double doubleA = Double.parseDouble(stA);
        double doubleC = Double.parseDouble(numC[i][1]);
        double doubleQ = doubleA / doubleC;
        int doubleRoundedQ = (int)Math.round(doubleQ);
        boolean doubleEven = doubleRoundedQ % 2 == 0;
        int doubleMIndex = doubleEven ? 1 : 0;
        String doubleOut = masterM[doubleMIndex][1].equals("○") ? "outA" : "outB";

        System.out.format("%d: double - A: %2.2f, C: %2.2f, Q: %2.2f, even(%d): %s ==> %s%n",
                i, doubleA, doubleC, doubleQ, doubleRoundedQ, doubleEven, doubleOut);

        quotient = Integer.valueOf(stA) / Integer.valueOf(numC[i][1]);

結果:
(出力されたものは、桁が揃っておらず見づらかったので、編集して読みやすくしてます)

9: int ---- A: 10,    C: 2,    Q: 5,    even(5): false ==> outA
9: double - A: 10.00, C: 2.00, Q: 5.00, even(5): false ==> outA
8: int ---- A:  9,    C: 1,    Q: 9,    even(9): false ==> outA
8: double - A:  9.00, C: 1.00, Q: 9.00, even(9): false ==> outA
7: int ---- A:  8,    C: 3,    Q: 2,    even(2): true  ==> outB <<<
7: double - A:  8.00, C: 3.00, Q: 2.67, even(3): false ==> outA >>>
6: int ---- A:  7,    C: 2,    Q: 3,    even(3): false ==> outA <<<
6: double - A:  7.00, C: 2.00, Q: 3.50, even(4): true  ==> outB >>>
5: int ---- A:  6,    C: 1,    Q: 6,    even(6): true  ==> outB
5: double - A:  6.00, C: 1.00, Q: 6.00, even(6): true  ==> outB
4: int ---- A:  5,    C: 3,    Q: 1,    even(1): false ==> outA <<<
4: double - A:  5.00, C: 3.00, Q: 1.67, even(2): true  ==> outB >>>
3: int ---- A:  4,    C: 2,    Q: 2,    even(2): true  ==> outB
3: double - A:  4.00, C: 2.00, Q: 2.00, even(2): true  ==> outB
2: int ---- A:  3,    C: 1,    Q: 3,    even(3): false ==> outA
2: double - A:  3.00, C: 1.00, Q: 3.00, even(3): false ==> outA
1: int ---- A:  2,    C: 3,    Q: 0,    even(0): true  ==> outB <<<
1: double - A:  2.00, C: 3.00, Q: 0.67, even(1): false ==> outA >>>
0: int ---- A:  1,    C: 2,    Q: 0,    even(0): true  ==> outB <<<
0: double - A:  1.00, C: 2.00, Q: 0.50, even(1): false ==> outA >>>

切り捨てと、四捨五入では、<<< >>> でマークした所に違いがありますが、どちらも期待している答えとは違いますね。仕様について、確認してもらえないでしょうか?


2016年3月21日 追記

②inM.csvファイルが空の場合エラー表示して通常終了したい
のですが次の処理に進んでしまいます。

回答が遅くなりました。

いまのプログラムは以下のような構造になっていますので、

public static void main(String[] args) {

    boolean emptyflgM = true; //inM判定マスタファイル空判定フラグ

    // ... 省略 ...

    fileError1:
    try {
        while ((stM = brM.readLine()) != null) {
            emptyflgC = false;

            // ... inM ファイルの読み込み
        }

        if (emptyflgM) {
            System.err.println("inM.csvファイルは空です。");
            break fileError1;
        }

    } catch(IOException e){
        // ...
    } finally {
        // ...
    }//finally

    // ... 次の処理

}

「inM.csvファイルは空です」を表示して、try 文から break しても、たしかに、次の処理と書かれた部分は実行されてしまいます。

エラー表示後、プログラムを正常終了させたいということなので、System.exit(0) を呼ぶのが良いと思います。break flieError と書く代わりに、System.exit(0) と書くと、(main メソッドを最後まで実行した時と同じように)Java仮想マシンの終了処理が行われ、プログラムが終了します。

引数の 0 は、正常終了を表します。ただ、このように入力ファイルに不備がある場合は、0 以外の値を返すことで、異常終了を表すのが一般的です。

今回のように、try 〜 catch 〜 finally の中から System.exit(0) を呼んだ場合、finally の部分もちゃんと実行されます。また、もっと大きなプログラムを書いていて、何らかの終了処理を行いたい時は、shutdown hook というものを設定することで、System.exit(int) を呼んだ時に、その処理を実行することができます。

なお、今回のプログラムだと、System.exit(0) ではなく、単に return と書いて、main メソッドから早期に抜け出す方法も使えます。ただ、この方法は応用がきかないので、おすすめはしません。今後、Java を学んでいくと、メソッドを分割するとか、クラスを分けるなどといった、プログラムを構造化することが必ず必要になります。そういう構造になってくると、inMファイルの読み込みも、main とは別のメソッドで行われるようになり、単にそのメソッドから return するだけでは、Java仮想マシンを終了させることができません。

さらに、今後学習していくなかで、エラー処理の方法についても調べてみてください。大きくわけて、2つの方法があります。

  1. エラーをメソッドからの戻り値で表す。例えば、Result といった名前のクラスを作り、メソッドが返す値を Resultオブジェクトにする。メソッドがエラーなく終了した時は、Resultオブジェクトに値(例:inM.csvファイルの内容)を格納して返す。エラーが起こった時は、Resultオブジェクトにエラーの内容を示す値を格納して返す。

  2. エラーを例外(Exception) で表す。例えば、EmptyFileException というような名前の例外クラスを作り、エラーが起こった時は、throw new EmptyFileException() というようにして例外を投げる。

Java は少し古い言語で、1の方法で呼び出し側(値を受け取った側)の処理が簡潔に書けないという問題があります。2は Java でエラー処理を行う中心的なやりかたですが、あまり例外を増やすと、プログラムの流れが分かりにくくなるという問題があります。

Java に慣れたら、1のような処理を簡潔に書ける、最近の言語もぜひ並行して学んでください。たとえば、Java で学んだ知識を活かせる、Scala という言語がおすすめです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/21 19:21

    tatsuya6502さん、ご回答いただきありがとうございました。
    この場合の仕様は、偶数 対 奇数ではなくて、偶数 対 それ以外の数ということになるのですね。
    ご指摘ありがとうございました。
    >①出力結果が2回づつ表示されています。
    この件ですがEclipseをクリーンしたら1回しか表示されなくなりました。
    お騒がせし申し訳ありませんでした、以後気を付けたいと思います。

    キャンセル

  • 2016/03/21 21:44

    完成したということで、よかったです!

    遅くなりましたが、エラー時のプログラム終了方法について、回答の方に追記しました。今後の参考にしてください。

    キャンセル

  • 2016/03/22 00:06

    tatsuya6502さん、例外処理の記述について非常に詳細なご説明とアドバイスをありがとうございました。
    例外についてもあまり理解できていないので少しづつ学んでいきたいと思います。
    いろいろと教えていただき本当にありがとうございました。

    キャンセル

0

既に回答もあるので、別の視点で書きます。
まず頑張って組んだ感じがだいぶ伝わりました。
過去自分もこういう組み方をしたことがあり苦労したことが思い出されました。

まるでどこかのプログラミングサイトみたいな問題ですが。


さて、本題です。

コードを見て感じたことを2点。
1.複数の問題解決をしようとされているようです。
→解決させたい問題ごとに作ってみてはいかがでしょうか。
取り急ぎ気づいたのは、存在を確認したファイルを読み込んで判定を行いその結果に従い、出力を行う これが一連の流れとして作られている点でした。
 例えば
・ファイルの存在を確認する処理。
・ファイルを読み込んでリストに入れる処理。
・リストを使って判定を行う処理。
・判定結果に基づき出力を行う処理。
せっかくisHanNumメソッドのように作られてることもあるので工夫してみてはいかがでしょうか。

2.勢いで作ってコンパイルエラーで悩んでるように見受けられます。
→自分の中でポイントをつくり分けて考えるように作って、それごとにコンパイルと確認するようにしてみてください。
必要なステップについては、【仕様内容】 を小学生でもわかる言葉で説明してみてください。
おのずと整理されてくると思います。

あとは、入力パターンを少なくして 確実に確認ができる状態を1度作ってみるとよいかもしれませんね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/03/20 17:09

    libさん、色々なアドバイスを下さりありがとうございました。
    1.の
    >解決させたい問題ごとに作ってみてはいかがでしょうか。
    というのはメソッド分割をした方が良いですよというお話でしょうか?
    isHanNumメソッドは流用させていただいていますので、現段階では自分で1からメソッドを作ることが出来ません。
    今後の課題にはなっていくと思いますので少しづつでも勉強していきます。
    2.の助言は正しくその通りだと思います。一気に作り上げているので、きっと頭の整理ができていないんですね。
    色々とアドバイス下さりありがとうございました。
    今後も頑張って勉強続けていきます。

    キャンセル

  • 2016/03/20 17:54

    >というのはメソッド分割をした方が良いですよというお話でしょうか?
    それも一考ですね。記述が冗長に見られたので、ひょっとしたらこれが混乱の原因なのかなと。

    キャンセル

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

  • ただいまの回答率 89.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる