从C ++中的txt文件读取数字行

时间:2019-01-30 23:00:10

标签: c++ file double ifstream

早上好,

我有一个学校作业,希望您能在这方面帮助我。 该程序的目标非常简单。计算数字的总和 在文件的每一行上,并在屏幕上显示N个最高的不同结果会导致rorder减少,其中N个结果的出现次数为N,用户将N作为参数提供(默认值= 3)。 因此,正如标题所述,我正在C ++中工作,我的程序必须从提供的txt文件中读取数字行(双精度)。我已经知道ifsream类型的概念,并设法打开了文件。我知道我可以使用>>运算符从文件中读取内容,但是每行的double数不是固定的,因此我无法进行简单的循环。到目前为止,这是我的样子:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

int main(){

    int nbresult=3;
    string filename;
    double tmp;

    cin >> filename;
    cin >> nbresult;

    ifstream file;
    file.open(filename.c_str());

    if(file.is_open())
    {
        cout << "Opening file: " << filename << endl;

        while(file.eof() == false)
        {
            vector<double> nbres;
            file >> tmp;
            nbres.push_back(tmp);
        }

        fichier.close();
    }
    else 
    {
        cout << "Erreur à l'ouverture !" << endl;
    }

    return 0;
}

所以我的想法是将数字放入向量中并进行求和,但是我意识到我需要为每一行创建向量的实例。另外,我的读取方法不允许我创建多个向量,因为它在读取时并未确认数字在不同的行中。

您能引导我找到有效的解决方案吗?我真的开始放松了。

提前谢谢! 哑光

1 个答案:

答案 0 :(得分:0)

如果我理解您的问题,并且仍然陷入困境,那么该过程的概述将只是用vector的最高总和(默认值:3)来填充n,该总和由{文件中的值。你想按降序排列的值。

每当您需要从文件中的一行中获取未知数量的值时(无论这些值是由逗号还是空格等分隔),您的方法都应该是将整行数据读入一个string,从该行创建一个stringsteam,然后循环从stringstream输入的值,直到EOF遇到stringstream

为什么使用stringstream而不是直接从文件中读取值? (答案:线控制)。由于cin会丢弃前导空格,而'\n'(换行符)是空格,因此无法确定何时到达直接从文件读取的行尾。通过先阅读该行然后创建一个stringstream,您可以简单地阅读,直到到达所创建的stringstream的末尾为止,并且将所有值都输入到一行中。

您需要在整个代码中维护的唯一vector是降序和的向量。从创建的stringstream读取每个值时,您可以简单地使用临时向量来将每个值存储在给定行中,然后在临时向量上调用accumulate以提供总和。

挑战是要在最终结果向量中保持总数的前X个,以在程序结尾输出。那里的方法实际上很简单。如果总和是第一笔总和,请使用push_back()进行存储。对于所有后续总和,请使用迭代器遍历向量,将已存储的内容与当前总和进行比较,直到总和大于向量的元素,然后调用.insert()方法将当前总和插入结果中通过迭代器引用的元素之前矢量。

完成后,只需使用自动调整的for循环输出结果向量即可。

有很多不同的方法来实现它,但是坚持上面的内容,您可以执行以下操作。对代码进行注释以帮助您逐步完成:

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <numeric>  /* for accumulate */

int main (int argc, char **argv) {

    if (argc < 2) {     /* validate at least filename given */
        std::cerr << "error: insufficient arguments\n"
                "usage: " << argv[0] << " filename (nresults: 3)\n";
        return 1;
    }

    std::string filename = argv[1],     /* string for filename */
                line;                   /* string to hold line */
    std::vector<int> results;           /* vector of results */
    std::ifstream f;                    /* input file stream */
    size_t nresults = 3, n = 0;         /* num of results, countner */

    if (argc >= 3)  /* if addition arg given, set nresults */
        nresults = std::stoi(argv[2]);

    f.open (filename);      /* open filename */
    if (! f.is_open()) {    /* validate file open for reading */
        perror (("error file open failed " + filename).c_str());
        return 1;
    }

    while (std::getline (f, line)) {    /* read each row of values */
        int val, sum;                   /* current value, line sum */
        std::vector<int> v;             /* vector to hold values */
        std::stringstream s (line);     /* create stringstream from line */
        while ((s >> val))              /* read each value */
            v.push_back (val);          /* add it to vector v */
        sum = accumulate (v.begin(), v.end(), 0);   /* sum values in v */
        if (results.empty())            /* if empty */
            results.push_back (sum);    /* just add */
        else    /* otherwise insert in decreasing order */
            for (auto it = results.begin(); it != results.end(); it++)
                if (sum > *it) {
                    results.insert (it, sum);
                    break;
                }
        if (results.size() > nresults)  /* trim excess elements */
            results.pop_back();
        n++;                            /* increment line count */
    }
    /* output results */
    std::cout << nresults << " greatest sums from " << n << " lines in " << 
                filename << '\n';
    for (auto& p : results)
        std::cout << " " << p;
    std::cout << '\n';
}

注意:,该代码期望文件名作为第一个参数,然后使用可选的参数表示要报告的最高总笔数-默认为3)< / p>

示例输入文件

以下输入仅是通过在0 - 999之间写入包含5个随机值的50行来产生的:

$ cat dat/50x5.txt
 106 114 604 482 340
 815 510 690 228 291
 250 341 774 224 545
 174 546 537 278 71
 706 139 767 320 948
 328 683 410 401 123
 140 507 238 744 990
 810 559 732 732 20
 24 982 361 30 439
 139 204 217 676 714
 288 615 853 287 935
 801 847 851 211 249
 206 583 756 676 328
 978 486 119 711 219
 139 967 433 733 997
 872 104 433 89 12
 147 609 627 0 897
 795 34 744 878 477
 225 84 61 982 761
 621 960 479 740 903
 930 112 870 364 77
 99 468 181 532 790
 193 911 399 53 912
 296 80 178 273 958
 887 498 274 180 712
 267 801 905 747 774
 40 677 118 911 273
 195 242 974 376 775
 764 801 686 163 854
 830 692 166 240 197
 124 128 927 399 540
 640 898 342 777 645
 348 817 555 466 960
 60 661 203 34 269
 978 798 302 896 194
 389 959 886 555 199
 83 680 559 10 311
 100 882 209 442 659
 87 22 709 874 488
 669 934 381 104 969
 650 314 999 952 211
 193 341 170 79 129
 601 394 809 161 637
 352 261 519 793 935
 411 112 957 352 986
 677 21 153 58 358
 122 708 672 353 892
 883 547 466 285 858
 595 887 253 636 48
 122 220 541 641 245

如果要验证的总和,可以使用一个短awk脚本 [1]

使用/输出示例

$ ./bin/vector_n_greatest dat/50x5.txt
3 greatest sums from 50 lines in dat/50x5.txt
 3703 3494 3302

$ ./bin/vector_n_greatest dat/50x5.txt 4
4 greatest sums from 50 lines in dat/50x5.txt
 3703 3494 3302 3269

$ ./bin/vector_n_greatest dat/50x5.txt 10
10 greatest sums from 50 lines in dat/50x5.txt
 3703 3494 3302 3269 3268 3168 3146 3126 3057 3039

仔细检查一下,如果还有其他问题,请告诉我。

脚注:

(1。)要输出已排序的行总和以进行验证,您可以使用简短的awk脚本和sort,例如

awk '{
    sum = 0
    for (i=1; i<=NF; i++)
        sum += $i
    printf "%-20s (%4d)\n", $0, sum
}' file | sort -r -b -k6.2

示例文件的awk输出将显示:

$ awk '{
>     sum = 0
>     for (i=1; i<=NF; i++)
>         sum += $i
>     printf "%-20s (%4d)\n", $0, sum
> }' dat/50x5.txt | sort -r -b -k6.2
 621 960 479 740 903 (3703)
 267 801 905 747 774 (3494)
 640 898 342 777 645 (3302)
 139 967 433 733 997 (3269)
 764 801 686 163 854 (3268)
 978 798 302 896 194 (3168)
 348 817 555 466 960 (3146)
 650 314 999 952 211 (3126)
 669 934 381 104 969 (3057)
 883 547 466 285 858 (3039)
 389 959 886 555 199 (2988)
 ...