У меня есть информация, которая выглядит так
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;
}
Я не уверен, что это лучший способ решить эту проблему.
Благодарю.
Вы переформулировали вопрос, который сделал его гораздо более понятным. Код, на мой взгляд, не самая важная вещь. Что вам нужно сделать, так это разложить всю задачу на работоспособные элементы, что сделает задачу решаемой.
Там может быть супер элегантный ответ на языках, отличных от 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
Дополнительное чтение: Мартин Фаулер: сборщик трубопроводов