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

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

ただいまの
回答率

90.50%

  • C#

    9065questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

1習慣で身につくC#言語のチャレンジ問題の解答コードがわからない

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,685

vnsa7221

score 31

前提・実現したいこと

現在C#を勉強するにあたり、「一週間で身につくC#言語」サイトを参照しながら勉強しております。
一通り基礎編の練習問題を解き終えたので、チャレンジ問題に挑戦しているところです。
現在Prob8-2において、重複判定をどのように実装すればよいかわからない状態です。

Prob8-1
a,b,cを、いずれも1以上100以下の整数とするとき、a*a+b*b=c*cを満たす、全てのa,b,cの組み合わせ全てと、その数を求め、画面に表示しなさい。ただし、a,bの数値の組み合わせが同じものも別のものとしてもかまわない。具体的には、a=3,b=4,c=5と、a=4,b=3,c=5は別の組み合わせとする。

Prob8-2←今ここを解いている
prob8-1.のデータから、重複を取り除いた組み合わせと、その数を表示するプログラムを作りなさい。具体的には、a=3,b=4,c=5と、a=4,b=3,c=5は同じものとみなす。

発生している問題・エラーメッセージ

重複する場合は表示させないという実装において、どのように実装すればよいのかわからない。

該当のソースコード

// prob8-1の解答
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Problem8_1
{
    class Program
    {
        static void Main(string[] args)
        {
            int a, b, c;

            for(a = 1; a <= 100; a++)
            {
                for(b = 1; b <= 100; b++)
                {
                    for(c = 1; c <= 100; c++)
                    {
                        int x = a * a;
                        int y = b * b;
                        int z = c * c;

                        if(x + y == z)
                        {
                            Console.WriteLine("a = {0} b = {1} c = {2}", a, b, c);
                        }
                    }
                }
            }
        }
    }
}
// prob8-2の解答
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Problem8_2
{
    class Program
    {
        static void Main(string[] args)
        {
            int a, b, c;
            int m = 0;
            int[,] ary = new int[1000, 3];

            for(a = 1; a <= 100; a++)
            {
                for(b = 1; b <= 100; b++)
                {
                    for(c = 1; c <= 100; c++)
                    {
                        int x = a * a;
                        int y = b * b;
                        int z = c * c;

                        if(x + y == z)
                        {
                            ary[m, 0] = a;
                            ary[m, 1] = b;
                            ary[m, 2] = c;

                            m++;
                        }
                    }
                }
            }

            //Console.WriteLine("{0}", ary.Length);

            for(int i = 0; i < ary.GetLength(0); i++)
            {
                if(ary[i, 0] != 0 && ary[i, 1] != 0 && ary[i, 2] != 0)
                {
                    Console.WriteLine("a = {0} b = {1} c = {2}", ary[i, 0], ary[i, 1], ary[i, 2]);
                }
            }
        }
    }
}

試したこと

①Prob8-1を最初利用しようとしたが、重複を判定する場合は一度該当する数値をデータとして保持しないと無理ではないかと思い、二次元配列に該当数字をpush

②該当数字を配列に格納したが、数値0,0,0が出てきてしまうのでいったんif文にて0,0,0を非表示←この部分もなんとかしたい。

③重複判定を行おうとしたが、どのようにすれば良いのか手詰まりとなってしまっている状態

補足情報(言語/FW/ツール等のバージョンなど)

現在勉強中のため、お手数をおかけしてしまい申し訳ございませんが、わかりやすいアドバイスを頂けると幸いでございます。
またもし別の方法や簡単な方法等ございましたらそちらに関するアドバイスもありがたいです。
よろしくお願いいたします。

追記

回答より頂いたアドバイスを参照に作成

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Problem8_2
{
    class Program
    {
        static void Main(string[] args)
        {
            int a, b, c;
            int m = 0;
            int[,] ary = new int[1000, 3];

            for(a = 1; a <= 100; a++)
            {
                for(b = 1; b <= 100; b++)
                {
                    for(c = 1; c <= 100; c++)
                    {
                        int x = a * a;
                        int y = b * b;
                        int z = c * c;

                        if(x + y == z)
                        {
                            // prob8-1より本制御文追加
                            if(a <= b)
                            {
                                Console.WriteLine("a = {0} b = {1} c = {2}", a, b, c);
                            }
                        }
                    }
                }
            }

            //Console.WriteLine("{0}", ary.Length);

            //for(int i = 0; i < ary.GetLength(0); i++)
            //{
            //    if(ary[i, 0] != 0 && ary[i, 1] != 0 && ary[i, 2] != 0)
            //    {
            //        Console.WriteLine("a = {0} b = {1} c = {2}", ary[i, 0], ary[i, 1], ary[i, 2]);
            //    }
            //}
        }
    }
}

ただなんとなく腑に落ちない部分があるので、頂いたアドバイスを参照にもう少し作ってみる

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

本件の場合重複しているかどうかはa,bの値のみのよって決まる(成立する組み合わせはa,bが決まればcは自ずと決まるので)と考えてよいと思います。さらにa,bを交換したものの重複を排除するなら最初からa <= bとなるような組み合わせについてのみチェックすることで重複排除そのものをしなくてよくなります。

(1) 問題文を読む限りは「望む結果が得られればよく、Prob8-1のアルゴリズムや結果のデータを利用する必要はない」と思います。

(2) 配列は一旦確保してしまうと、そこに有効なデータがあろうがなかろうが要素が存在してしまうので、「配列に格納されている有効な要素数」を別途変数で管理しないと「見てはいけない要素を見てしまう」結果になります。つまりfor(int i = 0; i < ary.GetLength(0); i++)は適切なループの仕方ではありません。for(int i = 0; i < m; i++)とするのが順当です。
なお、配列の多くの要素は多分無駄になりますし「1000要素で本当に大丈夫?」といった不安もあるのではないでしょうか?そんな場合は「可変長の列」を表現するクラスを使う方が素直に書けます。例えばListを用いれば次のように書けます。

var list = new List<int[]>();
...
if (x + y == z) {
  list.add(new int[] { a, b, c };
}
...
for (int i = 0; i < list.Count; i++) {
  ...
}

(3) 最初に述べた方法にすればやる必要がなくなります。もし練習のために重複排除の論理を作るなら...

for (int i = 0; i < m; i++) {
  bool found = false;
  for (int j = 0; j < i; j++) {
    if (i番目の解とj番目の解が重複している) {
      found = true; // 重複解が見つかったことを覚える
      break;
    }
  }
  if (!bound) {
    i番目の解を印字
  }
}


(なお重複排除を行うために実際の応用プログラミングでまともにループで書くことは少ないと思います。Dictionaryなどのクラスに解を登録した上で「このデータって登録済みですか?」と問い合わせるメソッドを用いれば簡単に求まるからです。そのようなクラスをうまく使うには「登録する要素が等しいかどうかを比較できるクラスにする」といったより応用的な設計が必要になってきます。しかしながらプログラミングの練習をする上ではまず自前でループを書いて論理を考える練習をすることは価値があると思います。)

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/06/27 15:50

    KSwordOfHasteさん回答ありがとうございます。
    可変長のListというものがあるんですね。その部分はまだ触ったことないので初めて知りました。
    今回いただいたアドバイスを参照として、せこいですがProb8-1のif(x + y == z)の下にif(a <= b)を追加することで期待していた結果を得ることを確認できました。

    ただこれだけだとなんか腑に落ちないというか、きちんと解いたという感じがしないので、頂いたアドバイスを参照にもう少し作りこんでいきたいと思います。
    ご丁寧なアドバイスありがとうございました。

    キャンセル

+1

問題文にあるモノをコードで表現する。この場合、a, b, c を「ピタゴラス数」としてまとめことを考えるとよいです。

2つのピタゴラス数 p1 と p2 に対して、「同じか」がしりたいので、IComparable を実装してください。

あとは HashSet に詰めれば解決。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/06/27 15:45

    koko_uさん回答ありがとうございます。
    すみません。自分の勉強不足もあり、それぞれの英単語が何を示すのかがよくわからない状態でした。
    この部分はググりながら進めるしかないですね。
    丁寧なアドバイスいただきありがとうございます。

    キャンセル

同じタグがついた質問を見る

  • C#

    9065questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。