夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

回文を判定する

本日の1日1問枠です。

〇1日1問プログラミング学習枠とは?

この枠ではプログラミングの勉強としてChatGPTにお題を出してもらいプログラムを組んでいく筆者の学習枠です。

今回はいくつか問題を出してくれたうちの1つ、回文を判定するプログラムを書いていきます。

〇お題

本日のお題はこちらです。

与えられた文字列が回文(前から読んでも後ろから読んでも同じ)かどうかを判定するプログラムを書いてください。

〇回答

筆者の回答は次になります。

using System;
using System.Linq;
                    
public class Program
{
    public static string input = "A man, a plan, a canal, Panama"; //ChatGPTを使用して作らせた回文サンプル
    public static void Main()
    {
    string result = new string(input.Where(char.IsLetter).ToArray()); //文字列からアルファベットのみを抽出
        for(int i= 0; i<= result.Length/2 ; i++)//回文なので文字数を2つに割って頭とお尻を比較
        {
            string a = result.Substring(i,1).ToLower();//頭からi番目の文字1文字を抽出して小文字に
            string b = result.Substring(result.Length - (1 + i),1).ToLower();//お尻からI番目の文字を抽出して小文字に
            
            if(a !=b)//aとbを比較
            {
              Console.WriteLine("回文ではありません");
                break;//回文じゃなかったらループを終了
            }
            if(i== result.Length/2)
            {
                Console.WriteLine("回文です");
            }
        }
    }
}

ここでのキーはWhere()です。

Where()は与えた要素から条件に基づいて要素を抽出することができます。

例えば次のような文では1,2,3,4,5の数字から2で割り切れる数=偶数のみを出力します。

 public static void Main()
    {
       List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
       var evenNumbers = numbers.Where(n => n % 2 == 0);

        foreach(var evenNumber in evenNumbers)
        {
           Console.WriteLine( evenNumber);      
        }
    }

今回の場合char.IsLetterを条件に指定し、これはアルファベットであるかどうかを判別しています。

new string(input.Where(char.IsLetter).ToArray());

〇ChatGPT先生の添削

提供されたコードは、与えられた文字列が回文であるかどうかを判定するために機能します。一般的には、文字列を正規化し、大文字と小文字を区別しないようにするために .ToLower() メソッドを使用するのは良い方法です。コードの評価を行いましょう。

以下は評価ポイントです:

正確な回文の判定: 提供されたコードは、与えられた文字列を正規化し、大文字と小文字を区別しないようにしています。ループ内で文字を比較し、回文でないと判定した場合には適切にメッセージを表示します。条件 if(i== result.Length/2) は文字列が回文の場合に "回文です" を表示するために使用されており、正確な回文の判定が行われているようです。

正確性: 与えられたコードは、多くの場合に正確に回文を判定するでしょう。ただし、句読点やスペースなどの非アルファベット文字は無視されます。これが意図した動作である場合、コードは正確です。

最適性: コードはシンプルで読みやすく、正確な判定を行います。ループ内で回文でないと判定した場合には、余分な比較を行わずに break することで、処理の効率を向上させています。

このコードは、回文の判定において基本的な要件を満たしてます。

そのうえでコードの最適化を依頼したところ次の回答を得られました。

大文字と小文字の区別を無視: 提供されたコードは文字を小文字に変換してから比較していますが、最初から大文字と小文字の区別を無視する方法もあります。これにより、 .ToLower() メソッドの呼び出しを省略できます。

string a = Char.ToLower(result[i]);
string b = Char.ToLower(result[result.Length - 1 - i]);

ChatGPT添削結果を踏まえたコード

public class Program
{
    public static string input = "A man, a plan, a canal, Panama";
    public static void Main()
    {
        bool isPalindrome = true;
    string result = new string(input.Where(char.IsLetter).Select(char.ToLower).ToArray());
        for(int i= 0; i<= result.Length/2 ; i++)
        {           
            if(result[i] != result[result.Length -1-i])           
            {
                isPalindrome = false;
           break;
            }
        }
        if(isPalindrome)
        {
            Console.WriteLine("回文です");
        }
        else
        {
            Console.WriteLine("回文ではありません");
        }
    }
}

改善点はfor文内にif文で、一致するかどうかをよりシンプルに求めています。

これを行うために最初の文字列の時点で小文字にしてしまっています。

string result = new string(input.Where(char.IsLetter).Select(char.ToLower).ToArray());

これにより処理量を減らし可読性を上げています。

本日の1日1問は以上です。

ChatGPTに問題作らせとかせるのは面白いのでしばらく続けてみようと思います。