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

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

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

Решение

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

Там может быть супер элегантный ответ на языках, отличных от C ++ — в Perl, Python, Ruby. Я напишу ответ на C #, так как типичная инфраструктура (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.

работает в rextester

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

0

Другие решения