我的信息看起来像这样
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
如您所见,信息按时间和ID排序。我希望能够做的是计算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 ++以外的语言中可能有一个超级优雅的答案 - 在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&amp; 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);
如您所见,这里有很多问题:文件输入,解析字符串,日期时间解析,查询,聚合。每个都需要特别小心。你绝对不想做的是花时间在低级细节上,比如终端处理。请考虑使用highest sufficient level of abstraction上的相应工具。
返回ParseColumns
和ToDateTime
。我把它们写成Extension Methods,这是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
);
}
}
这部分隐藏了一些代码中较为丑陋的部分,这些部分只是为了这个例子而“正常工作”。如果您正在编写的软件将被使用并稍后进行扩展,那么此类部件将在代码中的其他位置找到自己的方式,最好是behind abstractions。
如果您坚持使用C ++,您可能需要查看cpplinq。
运行