WedX - журнал о программировании и компьютерных науках

Чтение строк чисел из txt файла в С++

Доброе утро, парни,

У меня есть задание для школы, и я надеюсь, что вы могли бы помочь мне в этом. Цель программы очень проста. Вычислите сумму чисел в каждой строке файла и отобразите на экране N самых различных результатов в порядке убывания, где N — количество вхождений для каждого результата, N задается пользователем в качестве параметра (значение по умолчанию = 3). Итак, как следует из названия, я работаю на C++, и моя программа должна читать ряды чисел (двойные) из предоставленного txt-файла. Я уже знаю концепцию типов ifsream, и мне удалось открыть файл. Я знаю, что могу использовать оператор >> для чтения из файла, но количество удвоений в строке не фиксировано, поэтому я не могу сделать простой цикл. Вот как это выглядит до сих пор на моей стороне:

#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;
}

Итак, моя идея заключалась в том, чтобы поместить числа в вектор и суммировать, но я понял, что мне нужно будет создать экземпляр вектора для каждой строки. Кроме того, мой метод чтения не позволяет мне создавать несколько векторов, потому что он читает без учета того факта, что числа находятся в разных строках.

Можете ли вы, парень, привести меня к эффективному решению? Я действительно начинаю терять это, лол.

Заранее спасибо ! Мэтт

30.01.2019

  • while(file.eof() == false) 31.01.2019
  • Вариант 2 этого ответа должен вдохновить вас. 31.01.2019
  • Возвращаясь к этому, вам нужны эти цифры для чего-нибудь позже? Если нет, то вам не нужно их хранить. Вы можете суммировать их по мере чтения и подбрасывать сумму в вектор (при условии, что эти суммы понадобятся вам позже и вы не можете просто распечатать их сразу, а затем забыть). 31.01.2019
  • Вы можете #include <numeric> и использовать double sum = accumulate (nbres.begin(), nbres.end(), 0) для вычисления суммы каждой строки довольно удобно после заполнения nbres из каждой строки. 31.01.2019

Ответы:


1

Если я понимаю ваши вопросы, и если вы все еще застряли, обзор процесса будет просто заполнением vector верхними n суммами (по умолчанию: 3), вычисленными из каждой строки значений в файле. Вам нужно значение в порядке убывания.

Всякий раз, когда вам нужно получить неизвестное количество значений из строки в файле (независимо от того, разделены ли значения запятыми, пробелами и т. д.), ваш подход должен состоять в том, чтобы прочитать всю строку данных в 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';
}

(примечание: код ожидает имя файла в качестве 1-го аргумента, а затем принимает необязательный аргумент числа верхних сумм для отчета — по умолчанию используется 3)

Пример входного файла

Следующий ввод был просто получен путем записи 50 строк, содержащих 5 случайных значений между 0 - 999:

$ 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)
 ...
31.01.2019
Новые материалы

Как проанализировать работу вашего классификатора?
Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

Работа с цепями Маркова, часть 4 (Машинное обучение)
Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

Учебные заметки: создание моего первого пакета Node.js
Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..

ИИ в аэрокосмической отрасли
Каждый полет – это шаг вперед к великой мечте. Чтобы это происходило в их собственном темпе, необходима команда астронавтов для погони за космосом и команда технического обслуживания..


Для любых предложений по сайту: [email protected]