объединение информации на основе критериев с использованием C ++

0

У меня есть информация, которая выглядит так

No.      ID        DATE_EVENT   TIME_EVENT    EVENT   CODE
102995   018159871 07/08/2014   09:01:57      9008    1111
20398    018159871 07/08/2014   09:01:58      1000    1402
105541   018159871 07/08/2014   09:01:58      9210    1111
63492    018253609 07/08/2014   09:54:26      9008    905
37552    018253609 07/08/2014   09:54:45      9008    1111
9627     018253609 07/08/2014   09:54:48      9210    1111
112700   018253609 07/08/2014   09:54:48      1000    1402
50555    018253609 07/08/2014   09:55:56      1000    1401
63634    018253609 07/08/2014   09:55:56      9210    1111 
34551    018330948 07/08/2014   09:21:51      9008    905
47252    018330948 07/08/2014   09:22:15      9008    1111
3975     018330948 07/08/2014   09:22:17      1000    1402
24196    018330948 07/08/2014   09:22:17      9210    1111
111150   018342571 07/08/2014   09:40:08      9008    905
17119    018342571 07/08/2014   09:40:19      9008    1111
18658    018342571 07/08/2014   09:40:21      9210    1111
25654    018342571 07/08/2014   09:40:21      1000    1402

Как видите, информация сортируется по времени и идентификатору. То, что я хотел бы сделать, - подсчитать количество времени, затраченного на 9008 905 и 9008 1111 прежде чем перейти к следующему

и я читаю это так

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>

using namespace std;

vector<string> &SplitString(const string &s, char delim, vector<string> &elems)
{
    stringstream ss(s);
    string item;

    while (getline(ss, item, delim))
    {
        elems.push_back(item);
    }

    return elems;
}

int main(int argc, const char * argv[])
{

    ifstream CustJ("/Users/Rr/p/B/Sample 1.txt");

    string str;
    string elements;

    CustJ.seekg(0, ios::end);
    str.reserve(CustJ.tellg());
    CustJ.seekg(0, ios::beg);

    str.assign((istreambuf_iterator<char>(CustJ)),
               istreambuf_iterator<char>());    

    if (str.length() > 0)
    {

        vector<string> lines;
        SplitString(str, '\n', lines);

        vector<vector<string> > LineElements;

        for (auto it : lines)
        {

            vector<string> elementsInLine;

            SplitString(it, ',', elementsInLine);

            LineElements.push_back(elementsInLine);
         }

        //this displays each element in an organized fashion

        //for each line
        for (auto it : LineElements)
        {
            //for each element IN that line
            for (auto i : it)
            {
                //if it is not the last element in the line, then insert comma 
                if (i != it.back())
                    std::cout << i << ',';
                else
                    std::cout << i;//last element does not get a trailing comma
            }
            //the end of the line
            std::cout << '\n';
        }
    }
    else
    {
        std::cout << "File Is empty" << std::endl;
        return 1;
    }



    system("PAUSE");
    return 0;
}

Я не уверен, что это лучший способ подойти к этой проблеме.

Благодарю.

  • 0
    Определите, что означает «корзина строк». Вы должны знать лучше, если вы правильно прочитали информацию, потому что у вас есть исходный текстовый файл и выходные данные программы, у нас нет ни того, ни другого.
  • 0
    Как только мы узнаем, что вы действительно хотите сделать, вам действительно нужно использовать C ++? Проверьте python / ruby / даже C # + LINQ для этой задачи.
Показать ещё 3 комментария
Теги:
binning

1 ответ

0

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

На языках, отличных от C++, может быть супер элегантный ответ на Perl, Python, Ruby. Я напишу ответ на С#, так как типичная инфраструктура (IDE) может вам помочь, а LINQ (языковой интегрированный запрос) - ваш друг в таких задачах.

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

Первый компонент - это вход из файла. В декларативной форме:

var lines = File
    .ReadAllLines("input.txt", Encoding.Default)
    .Skip(1);

Нам нужно будет рассчитать промежутки времени от смежных дат-времени, поэтому мы их соединим:

var event_tuples = lines
    .Zip(lines.Skip(1), (start, end) => new { Start = start, End = end });

Затем мы можем структурировать данные для более четкого запроса:

var entries = event_tuples
    .Select(x => {
        var start_data = x.Start.ParseColumns();
        var end_data = x.End.ParseColumns();
        var duration = end_data.ToDateTime() - start_data.ToDateTime();

        return new
        {
            No=start_data[0],
            Id=start_data[1],
            Duration = duration,
            Event = start_data[4],
            Code = start_data[5]
        };
    })
;

Здесь вы можете увидеть использование предыдущего структурированного вывода запроса: .Start и .End. Подробнее о ParseColumns и ToDateTime позже.

Теперь к вашему примеру запрос:

подсчитайте количество времени, затраченного на 9008 905 и 9008 1111 Сначала найдите соответствующие события

var query = entries
    .Where(x => x.Event == "9008"
                && new[] { "905", "1111" }.Contains(x.Code))
;

Console.WriteLine("{0} events found",query.Count());

а затем вычислить общую продолжительность:

var total_duration = query
    .Select(x=>x.Duration)
    .Aggregate((a, b) => a + b);

Console.WriteLine("total duration: {0}", total_duration);

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

Вернемся к ParseColumns и ToDateTime. Я написал их как методы расширения, которые являются основой LINQ и помогают писать декларативный код, даже их использование может быть спекулятивным здесь. На других языках существуют другие механизмы, которые позволяли бы такую читаемость.

Пример: реализация конкретных задач здесь:

static class Extensions {
    public static string[] ParseColumns(this String line)
    {
        return line.Split(new char[] { ' ' },
                          StringSplitOptions.RemoveEmptyEntries);
    }

    public static DateTime ToDateTime(this String[] line)
    {
        const string datetime_format = "dd/MM/yyyy H:mm:ss";
        return DateTime.ParseExact(
            line[2] + " " + line[3], 
            datetime_format, 
            CultureInfo.InvariantCulture
        );
    }
}

Это частично скрывает некоторые более уродливые части кода, которые "просто заставляют его работать" для этого примера. Если программное обеспечение, которое вы пишете, будет использоваться и впоследствии расширено, такие части найдут свой путь где-то еще в коде, предпочтительно, за абстракциями.

Если вы придерживаетесь C++, вы, вероятно, захотите взглянуть на cpplinq.

управляемый в реестре

Дополнительное чтение: Мартин Фаулер: сборник

Ещё вопросы

Сообщество Overcoder
Наверх
Меню