首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用C++函数编程预计算n型tic趾板的得奖组合

用C++函数编程预计算n型tic趾板的得奖组合
EN

Code Review用户
提问于 2019-07-05 17:39:32
回答 1查看 153关注 0票数 3

此代码预先计算n个大小的tic tac脚趾板的获奖组合。

我首先使用命令式方法创建了我的函数。这正是我大多数时候自然地编写代码的方式。然后我试着用“我想完成什么?”来思考这个问题。方法,而不是“我想要它做什么?”最后,我想我还是采用了一种命令式的方法,只使用STL算法作为循环。

必须采取的办法:

代码语言:javascript
复制
std::vector<std::vector<int>> rules3(const int x){
    using namespace std;

    vector<vector<int>> seqs;
    for(int n=0; n<x; ++n){
        vector<int> seq;
        for(int m=0; m<x; ++m){
            seq.push_back(n*x+m);
        }
        seqs.push_back(seq);
    }
    for(int n=0; n<x; ++n){
        vector<int> seq;
        for(int m=0; m<x; ++m){
            seq.push_back(n+x*m);
        }
        seqs.push_back(seq);
    }
    vector<int> seq;
    for(int n=0; n<x; ++n){
        seq.push_back(n*x+n);
    }
    seqs.push_back(seq);
    seq.clear();
    for(int n=0; n<x; ++n){
        seq.push_back(x-1+n*(x-1));
    }
    seqs.push_back(seq);

    return seqs;
}

变得更有功能:

代码语言:javascript
复制
std::vector<std::vector<int>> rules2(const int x){
    using namespace std;

    vector<vector<int>> seqs;
    vector<int> iter(x);
    iota(iter.begin(), iter.end(), 0);

    for(auto n: iter){
        vector<int> seq;
        for(auto m: iter){
            seq.push_back(n*x+m);
        }
        seqs.push_back(seq);
    }
    for(auto n: iter){
        vector<int> seq;
        for(auto m: iter){
            seq.push_back(n+x*m);
        }
        seqs.push_back(seq);
    }
    vector<int> seq;
    seq.clear();
    for(auto n: iter){
        seq.push_back(n*x+n);
    }
    seqs.push_back(seq);
    seq.clear();
    for(auto n: iter){
        seq.push_back(x-1+n*(x-1));
    }
    seqs.push_back(seq);

    return seqs;
}

功能方法?(仍然觉得有必要):

代码语言:javascript
复制
std::vector<std::vector<int>> rules1(const int x){
    using namespace std;

    vector<vector<int>> seqs;
    vector<int> iter(x);
    iota(iter.begin(), iter.end(), 0);

    transform(iter.begin(), iter.end(), back_inserter(seqs), [&](const int& n){
        vector<int> seq;
        transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& m){
            return n*x+m;
        });
        return seq;
    });
    transform(iter.begin(), iter.end(), back_inserter(seqs), [&](const int& n){
        vector<int> seq;
        transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& m){
            return n+x*m;
        });
        return seq;
    });
    vector<int> seq;
    transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& n){
        return n*x+n;
    });
    seqs.push_back(seq);
    seq.clear();
    transform(iter.begin(), iter.end(), back_inserter(seq), [&](const int& n){
        //return (x-n-1)*x+n; // 6,4,2
        return x-1+n*(x-1); // 2,4,6
    });
    seqs.push_back(seq);

    return seqs;
}

打印时的输出:

代码语言:javascript
复制
rules3
std::vector(0, 1, 2)
std::vector(3, 4, 5)
std::vector(6, 7, 8)
std::vector(0, 3, 6)
std::vector(1, 4, 7)
std::vector(2, 5, 8)
std::vector(0, 4, 8)
std::vector(2, 4, 6)
rules2
std::vector(0, 1, 2)
std::vector(3, 4, 5)
std::vector(6, 7, 8)
std::vector(0, 3, 6)
std::vector(1, 4, 7)
std::vector(2, 5, 8)
std::vector(0, 4, 8)
std::vector(2, 4, 6)
rules1
std::vector(0, 1, 2)
std::vector(3, 4, 5)
std::vector(6, 7, 8)
std::vector(0, 3, 6)
std::vector(1, 4, 7)
std::vector(2, 5, 8)
std::vector(0, 4, 8)
std::vector(2, 4, 6)
EN

回答 1

Code Review用户

发布于 2019-07-10 02:18:42

这里有一些建议。这将使用范围-v3库并假定

代码语言:javascript
复制
#include <range/v3/all.hpp>

namespace view = ranges::view;
  1. 请包括#includes,并提供一个小的测试计划在未来。您可能已经编写了它们,那么为什么不发布它们以节省审阅者的时间呢?
  2. 对于索引来说,int可能太小了。考虑使用std::size_t。您可以为灵活性定义类型别名。使用index_t = std::size_t;
  3. std::vector<std::vector<index_t>>类型多次发生。通过使用rule_t = std::vector编写rules_t =std::vector来节省时间;
  4. "n \times n板“的概念只有在n是正整数时才有意义。因此,强制执行预条件n \ge 1.而且,x这个名字有点模糊。size可能更好。rules_t规则(index_t大小){ if ( == 0)抛出std::invalid_argument{“.”};// .}
  5. rules(1)当前返回{{0}, {0}, {0}, {0}},这显然是错误的。它应该返回{{0}}。您的一般逻辑是"n行+ n列+ 2对角线“,它只适用于n \ge 2。最简单的方法是特例: rules_t规则(index_t大小){ // .如果(大小为== 1)返回{0}};}
  6. 按照前面的要点,为什么不使用单独的函数来明确逻辑呢?rules_t规则(index_t大小){ // .否则{自动行=rules_row(大小);auto列=rules_column(大小);自动对角线=rules_diagonal(大小);返回ranges::to(视图:concat(行、列、对角线));}} view::concat将三个向量连接起来,ranges::to将结果转换为所需的返回类型。(请注意,view::concat禁用了rvalue以防止悬空迭代器,因此我们首先存储子向量。)
  7. rules_row函数易于编写: rules_t rules_row(index_t size) {返回视图::ints(index_t(0),size * size)查看::块( size );} view::ints生成一个左包含整数的{0, 1, 2, ..., size * size - 1}序列,view::chunk(size)将其分解为大小为size的每个块。
  8. rules_column函数有点棘手,因为Range库没有提供像chunk这样的函数。我们确实有一个函数stride,所以我们可以编写一个手册“循环”:(我花了很长时间才弄明白这一点,所以告诉我是否有更好的方法!)rules_t rules_column(index_t大小){返回视图::ints(index_t(0),size) index_t视图::transform(={返回视图:ints(index_t(Col),size * size)视图::size( size);} view::ints(index_t(0), size)生成列号。他们中的每一个都被传递给羔羊。lambda为每个列返回相应的规则。
  9. rules_diagonal函数比较简单: rules_t rules_diagonal(index_t size) {返回{ view::ints(index_t(0),size) ints视图::transform(={返回r* (size + 1);};}),视图:ints(index_t( 1),size +1)\\视图::transform(={返回r* (size - 1);}) };}在这里,我们总是有两个规则:一个用于主对角线{0 * size + 0,1* size + 1,2* size + 2,.,.,(size - 1) * size + (size - 1)},它等价于{0,1,2,……大小- 1} *(大小+ 1);第二对角线{size - 1,2* size - 2,3* size - 3,.大小-(大小- 1)},等于{1,2,3,.,大小+ 1} *(大小- 1)
  10. 将所有内容组合在一起:# #包含命名空间视图=范围: index_t = std::size_t;使用rule_t = std::vector;使用rules_t = std::vector;rules_t rules_row(index_t大小){返回视图::ints(index_t(0),size * size)视图::区块(大小);} rules_t rules_column(index_t大小){返回视图::ints(index_t(0),size) {index_t视图:={返回视图:ints(index_t(Col),size * size)视图::stride( size);});} rules_t rules_diagonal(index_t size) {返回{ view::ints(index_t(0),size) index_t视图:transform(={返回r* (size + 1);};}),视图:ints(index_t( 1),size +1)查看:transform(={返回r* (size - 1);}) };} rules_t规则(index_t大小){ if ( == 0)抛出std::invalid_argument{“委员会不能有0”};否则,如果(大小== 1)返回{{0};否则(自动行=rules_row(大小);自动列=rules_column(大小);自动对角线=rules_diagonal(大小);返回视图::concat(行、列、对角线);} (现场演示,测试size = 1, 2, 3, ..., 10函数)
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/223578

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档