ソースコードと因数分解

ちょっと長文書くぞ巡回 - いろきゅう.jp // Programmable maiden traumend 〜夢見るPG〜 の中ほどから続き

プログラマ因数分解概念は必要だと私は思います。即興の例であんまり良くないのですが^^;

ある値の配列から、最小値・最大値を取得したい場合…

int main()
{
    // いろきゅうお兄さんな数値列
    int    anValues[]      = { 1, 6, 9, 0, 2, 3 };
    size_t nValueArraySize = sizeof(anValues) / sizeof(anValues[0]);
    int    nMinValue;
    int    nMaxvalue;

    // 最小値検索
    nMinValue = anValues[0];
    for(size_t i = 1; i < nValueArraySize; ++i)
    {
        if(anValues[i] < nMinValue)
            nMinValue = anValues[i];
    }

    // 最大値検索
    nMaxValue = anValues[0];
    for(size_t i = 1; i < nValueArraySize; ++i)
    {
        if(anValues[i] > nMaxValue)
            nMaxValue = anValues[i];
    }

    return 0;
}

なんて書いてしまう人もいるかとは思いますが、ここは「配列を走査している」「なんか比較して値を取得してる」という共通部分に着目し、このアルゴリズムの部分を外部の関数に出しちゃう訳ですよ。すると

int ReturnMinValue(int l, int r)
{
     return l < r ? l : r;
}

int ReturnMaxValue(int l, int r)
{
    return l > r ? l : r;
}

int ScanValue(const int* anValueArray, size_t nArraySize, int (*fnBinary)(int, int))
{   // エラーチェックしてないけどまぁいいや^^; -> ぬるぽとか

    int nRetValue = anValueArray[0];
    for(size_t i  = 1; i < nArraySize; ++i)
        nRetValue = fnBinary(nRetValue, anValueArray[i]);

    return nRetValue;
}

int main()
{
    // いろきゅうお兄さんな数値列
    int    anValues[]      = { 1, 6, 9, 0, 2, 3 };
    size_t nValueArraySize = sizeof(anValues) / sizeof(anValues[0]);
    int    nMinValue;
    int    nMaxvalue;

    // 配列と比較用関数を渡して、最小値と最大値検索
    nMinValue = ScanValue(anValues, nValueArraySize, &ReturnMinValue);
    nMaxValue = ScanValue(anValues, nValueArraySize, &ReturnMaxValue);

    return 0;
}

こんな具合。「なんじゃこりゃ!悪化しとるやん!」なんて思われるかもしれませんが、実際の作業中は関数単位で物事考えていく訳ですから(割と自論^^;)

int main()
{
    // いろきゅうお兄さんな数値列
    int    anValues[]      = { 1, 6, 9, 0, 2, 3 };
    size_t nValueArraySize = sizeof(anValues) / sizeof(anValues[0]);
    int    nMinValue;
    int    nMaxvalue;

    // 配列と比較用関数を渡して、最小値と最大値検索
    nMinValue = ScanValue(anValues, nValueArraySize, &ReturnMinValue);
    nMaxValue = ScanValue(anValues, nValueArraySize, &ReturnMaxValue);

    return 0;
}

を頭の中で管理すればよくなります。ScanValue という値を取得する為の処理を(あんまり適してない関数名だなぁ)名前を付けて外部に出した事により、元のfor文つかってごにょごにょしてるコードよりずっと分りやすくなってると私は思います。


この「共通部分を見つけ出して外に出す」という点で「ソースコード因数分解」だと私は思ってるんですが、どーでしょーか。…少なからず因数はおかしいかも。


ちなみにですが、同様でもっと高機能な関数は C++ に標準で定義されているので^^;、私が書くとしたら

template<typename T, size_t N>
size_t GetArraySize(T (&t)[N]){ return N; }

int main()
{
    // いろきゅうお兄さんな数値列
    const int  anValues[] = { 1, 6, 9, 0, 2, 3 };
    const int* pValuesEnd = anValues + GetArraySize(anValues);
    const int  nMinValue  = *std::min_element(anValues, pValuesEnd);
    const int  nMaxvalue  = *std::max_element(anValues, pValuesEnd);

    return 0;
}

とか。

stlが絡んできたら

int main()
{
    typedef std::vector<int> TIntVect;

    // なんか値が入るとする
    TIntVect stlVect;

    const TIntVect::value_type nMinValue = *std::min_element(stlVect.begin(), stlVect.end());
    const TIntVect::value_type nMaxValue = *std::max_element(stlVect.begin(), stlVect.end());

    return 0;
}

とかいう感じですかねー。:P

参考 / 元のコード

int main()
{
    // いろきゅうお兄さんな数値列
    int    anValues[]      = { 1, 6, 9, 0, 2, 3 };
    size_t nValueArraySize = sizeof(anValues) / sizeof(anValues[0]);
    int    nMinValue;
    int    nMaxvalue;

    // 最小値検索
    nMinValue = anValues[0];
    for(size_t i = 1; i < nValueArraySize; ++i)
    {
        if(anValues[i] < nMinValue)
            nMinValue = anValues[i];
    }

    // 最大値検索
    nMaxValue = anValues[0];
    for(size_t i = 1; i < nValueArraySize; ++i)
    {
        if(anValues[i] > nMaxValue)
            nMaxValue = anValues[i];
    }

    return 0;
}