首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何向filestream写入自定义数据类型(std::数组中填充了std::pairs)

如何向filestream写入自定义数据类型(std::数组中填充了std::pairs)
EN

Stack Overflow用户
提问于 2019-01-12 17:43:41
回答 3查看 189关注 0票数 0

我对c++非常陌生,我正在建立一个研究某些基因突变的模型。我的“基因”被定义为两个双倍的函数,a和b。单个基因被保存在std::结对格式中。整个基因组由四个基因组成,这些基因被收集在一个std:数组中。

我对基因进行了一些更改,并希望将这些信息写入文本文件中进行分析。我目前实现这一点的方式是乏味的。我有单独的函数(总共8),为数组中的每一个I收集诸如gi.first、g[i[.second等)之类的信息。我觉得这样做更有效率。

相关守则:

数据类型声明:

代码语言:javascript
复制
using gene = std::pair<double, double>;
using genome = std::array<gene, 4>;

函数中,我创建了一个名为g的基因组:

代码语言:javascript
复制
genome Individual::init_Individual()
{
    double a1, a2, a3, a4 = -1.0;
    double b1, b2, b3, b4 = 0.0;
    gene g1{ a1,b1 };
    gene g2{ a2,b2 };
    gene g3{ a3,b3 };
    gene g4{ a4,b4 };
    genome g{g1,g2,g3,g4};
    return g;
}

收集功能示例:

代码语言:javascript
复制
double get_Genome_a1() { return g[0].first; };

函数,其中我将信息写入文本文件:

代码语言:javascript
复制
void Individual::write_Statistics(unsigned int &counter)
{
    //Generate output file stream
    std::ofstream ofs;
    ofs.open("data.txt", std::ofstream::out | std::ofstream::app);    
    ofs << counter << std::setw(14) << get_Genome_a1() <<     std::setw(14)
        << get_Genome_a2() << std::setw(14) << get_Genome_b1() <<
        std::setw(14) << get_Genome_b2() << "\n";
}
ofs.close();

}

因此,本例中数据文件的最终结果如下所示:

1 a1 a2 b1 b2

2 a1 a2 b1 b2

3 a1 a2 b1 b2

等等

我的问题是:

  1. 我目前将这两个双倍存储在std::偶数中,这是我在std::数组中收集的。这是一种有效的存储机制,还是可以改进?
  2. 是否有一种方法直接引用我的自定义数据类型“基因组”中的单个元素,只使用一个函数以与我现在所做的完全相同的方式编写每个元素(每个元素之间有14个空格)?伪代码中的内容,如: get_Genome() {返回g;};,当您调用它时,可以指定元素,例如: get_Genome(.first),它将是存储在数组第一对中的第一个值。

很高兴学习,任何洞察力都会被欣赏。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-01-12 18:35:17

您的array看起来不错,但是在这种情况下使用std::pair可能会使它更加繁琐。我会创建两个简单的类或结构,一个代表一个基因,另一个代表你的基因组。我还是会用array。这门课看起来可能是这样的:

代码语言:javascript
复制
#include <array>

const int genesPerGenome = 4; // change this to set how many...

struct Gene {
    double a_;
    double b_;

    Gene() = default;
    Gene(double a, double b) : a_(a), b_(b) {}
};

struct Genome {
    std::array<Gene, genesPerGenome> genome_;
    int geneCount_{0};

    Genome() = default;

    void addGene(const Gene& gene) {
        if ( geneCount_ >= genesPerGenome ) return;
        genome_[geneCount_++] = gene; // post increment since we added one
    }
}; 

然后我就有了一个独立的功能来生成你的基因组

代码语言:javascript
复制
void generateGenome( Genome& genome ) {
    for (int i = 0; i < 4; i++) {
        // When looking at your example; I notices that the genes were all
        // initialized with [-1.0,0.0] so I used Gene's constructor to init
        // them with those values.
        Gene gene(-1.0, 0.0);
        genome.addGene(gene);
    }
}

然后,为了将它们结合在一起,我将把它们打印到控制台进行演示。然后,您可以采用这种方法,并将其应用于将进行的任何计算,然后将结果写入文件。

代码语言:javascript
复制
#include <array>
#include <iostream>

int main() {
    Genome genome;
    generateGenome( genome );

    // printing to console here is where you would do your calculations then write to file
    for ( int i = 0; i < 4; i++ ) {
        if ( i >= genome.geneCount_ ) break; // prevent accessing beyond array bounds
        std::cout << (i+1) << " [" << genome.genome_[i].a_ << "," << genome.genome_[i].b_ << "]\n";
    }

    return 0;
}

-输出--没有计算,只有初始化值:

代码语言:javascript
复制
1 [-1,0]
2 [-1,0]
3 [-1,0]
4 [-1,0]

也许这个能帮上忙。从这里开始,您可以编写一个operartor<<()函数,它将接受一个ostream引用对象和一个对Genome的const引用,从那里您应该能够在一个函数调用中打印出整个Genome文件。

-编辑-

用户t.niese留下了一个我忽略了的有效点的评论。我在addGene()函数中使用了一个静态变量。只要您只使用单个基因组,它就能正常工作,但是如果您有多个Genome对象,那么每次调用addGene()函数时,这个值都会增加,而且由于addGene()函数中if语句的条件,您将无法向每个基因组中添加超过gene的值。

我修改了上面的原始代码来修正这个限制。在这里,我删除了静态变量,我引入了两个新变量,一个是const int,它表示每个基因组的基因数,因为它将用于定义数组的大小,并检查要添加多少个基因到基因组中。我添加的另一个变量是Genome类本身的一个成员变量,它跟踪每个基因组对象有多少基因。

票数 1
EN

Stack Overflow用户

发布于 2019-01-12 17:48:07

你的储藏室很好。pairarray都不需要间接/动态分配,因此这对缓存局部性很好。

至于引用元素,不,不完全是这样。您可以对FIRST成员进行枚举,然后将它作为另一个参数传递给get_Genome。但是,老实说,在我看来这不值得。

总的来说,你的方法在我看来很不错。我唯一的建议是:

重用一个ofstream

…而不是为每个示例打开和关闭文件。你应该看到从这一变化中速度有了很大的提高。

您可以在您的main或其他什么,并让write_Statistics采取std::ostream&,这也会更灵活!

初始化得更快一点

init_Individual中的所有声明都可能得到优化,但为什么要冒这个风险呢?以下内容很有表现力:

代码语言:javascript
复制
genome Individual::init_Individual()
{
    const double a = -1.0;
    const double b =  0.0;

    return {{a, b}, {a, b}, {a, b}, {a, b}};
}

值得注意的是,您的double初始化是错误的:您只是在初始化a4b4;您的编译器应该对此发出警告。但是,正如所示,我们并不需要所有这些,因为它们的目的是具有相同的值!

票数 2
EN

Stack Overflow用户

发布于 2019-01-12 19:05:35

这里有一个例子,说明了我在注释中通过重载操作符[]的意思。

代码语言:javascript
复制
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>


class Genome {
    public:
        typedef std::pair<double, double> gene;

    private:
        double a1 = -1.0, a2 = -1.0, a3 = -1.0, a4 = -1.0;
        double b1 = 0.0, b2 = 0.0, b3 = 0.0, b4 = 0.0;

        gene g1{ a1,b1 };
        gene g2{ a2,b2 };
        gene g3{ a3,b3 };
        gene g4{ a4,b4 };

  public:
      Genome() {}

      const double operator[] (std::string l) const {
          if (l == "a1") {return g1.first;}
          else if (l == "b1") {return g1.second;}
          else if (l == "a2") {return g2.first;}
          else if (l == "b2") {return g2.second;}
          else if (l == "a3") {return g3.first;}
          else if (l == "b3") {return g3.second;}
          else if (l == "a4") {return g4.first;}
          else if (l == "b4") {return g4.second;}
          else {
              throw std::invalid_argument("not valid label");
          }
      }

      void setvalue(std::string l, double x) {
          if (l == "a1") {g1.first = x;}
          else if (l == "b1") {g1.second = x;}
          else if (l == "a2") {g2.first = x;}
          else if (l == "b2") {g2.second = x;}
          else if (l == "a3") {g3.first = x;}
          else if (l == "b3") {g3.second = x;}
          else if (l == "a4") {g4.first = x;}
          else if (l == "b4") {g4.second = x;}
          else {
              throw std::invalid_argument("not valid label");
          }
      }

    void write_Statistics(unsigned int counter) {
        std::ofstream ofs;
        ofs.open("data.txt", std::ofstream::out | std::ofstream::app);
        ofs << counter
        << std::setw(14) << (*this)["a1"] << std::setw(14) << (*this)["a2"]
        << std::setw(14) << (*this)["b1"] << std::setw(14) << (*this)["b2"] << "\n";
        ofs.close();
    }
    }
};

我不知道你是否会发现通过标签而不是索引来获取单个基因是否有用,但这就是这种过载的作用。

代码语言:javascript
复制
int main(int argc, char **argv) {
    Genome a = Genome();
    std::cout << a["b1"] << std::endl; #this prints 0

    a.setvalue("b2", 3.0);
    std::cout << a["b2"] << std::endl; #this prints 3

    a.write_Statistics(0);
    return 0;
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54162258

复制
相关文章

相似问题

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