C++ C++;在关键字段上连接两个管道分割文件
我目前正在尝试创建一个C++函数,将两个管分文件连接在一个或两个关键字段上超过10000个记录。 这些恶魔看起来像C++ C++;在关键字段上连接两个管道分割文件,c++,arrays,join,vector,ifstream,C++,Arrays,Join,Vector,Ifstream,我目前正在尝试创建一个C++函数,将两个管分文件连接在一个或两个关键字段上超过10000个记录。 这些恶魔看起来像 P2347|John Doe|C1234 P7634|Peter Parker|D2344 P522|Toni Stark|T288 及 要加入字段1和3,预期输出应显示: P2347|C1234|John Doe|Bruce Wayne P522|T288|Toni Stark|Terminator 我目前考虑的是使用set
P2347|John Doe|C1234
P7634|Peter Parker|D2344
P522|Toni Stark|T288
及
要加入字段1和3,预期输出应显示:
P2347|C1234|John Doe|Bruce Wayne
P522|T288|Toni Stark|Terminator
我目前考虑的是使用set/array/vector读入文件并创建如下内容:
P2347|C1234>>John Doe
P522|T288>>Toni Stark
及
然后使用第一部分的滑动作为键,并将其与第二组/向量/数组匹配
我目前拥有的是:读入第一个文件,并根据集合逐行匹配第二个文件。它采用整条线并与之匹配:
#include iostream>
#include fstream>
#include string>
#include set>
#include ctime>
using namespace std;
int main()
{
clock_t startTime = clock();
ifstream inf("test.txt");
set lines;
string line;
for (unsigned int i=1; std::getline(inf,line); ++i)
lines.insert(line);
ifstream inf2("test2.txt");
clock_t midTime = clock();
ofstream outputFile("output.txt");
while (getline(inf2, line))
{
if (lines.find(line) != lines.end())
outputFile > a;
return 0;
}
我很乐意接受任何建议。如果有更好(更快)的方法,我也很乐意改变整个概念。速度至关重要,因为可能有超过1000万条记录
编辑:另一个想法是拿一张地图,把钥匙作为钥匙——但这可能会慢一点。有什么建议吗
非常感谢你的帮助 我尝试了多种方法来完成这项任务,但迄今为止没有一种方法是有效的: 将所有内容读入一个集合,并将键字段解析为一种格式:keys>>模拟数组类型集合的值。解析花了很长时间,但内存使用率相对较低。未完全开发的代码:
#include \
#include \
#include \
#include \
#include \
#include \
#include \
std::vector &split(const std::string &s, char delim, std::vector &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector split(const std::string &s, char delim) {
std::vector elems;
split(s, delim, elems);
return elems;
}
std::string getSelectedRecords(std::string record, int position){
std::string values;
std::vector tokens = split(record, ' ');
//get position in vector
for(auto& s: tokens)
//pick last one or depending on number, not developed
values = s;
return values;
}
int main()
{
clock_t startTime = clock();
std::ifstream secondaryFile("C:/Users/Batman/Desktop/test/secondary.txt");
std::set secondarySet;
std::string record;
for (unsigned int i=1; std::getline(secondaryFile,record); ++i){
std::string keys = getSelectedRecords(record, 2);
std::string values = getSelectedRecords(record, 1);
secondarySet.insert(keys + ">>>" + values);
}
clock_t midTime = clock();
std::ifstream primaryFile("C:/Users/Batman/Desktop/test/primary.txt");
std::ofstream outputFile("C:/Users/Batman/Desktop/test/output.txt");
while (getline(primaryFile, record))
{
//rewrite find() function to go through set and find all keys (first part until >> ) and output values
std::string keys = getSelectedRecords(record, 2);
if (secondarySet.find(keys) != secondarySet.end())
outputFile > a;
return 0;
}
它目前使用的不是“管道分割”,而是“空间分割”,但这应该不是问题。读取数据非常快,但解析数据需要花费大量时间
另一种选择是使用多重地图。与此概念类似,关键字段指向值,但此字段非常低且占用大量内存
#include \
#include \
#include \
#include \
#include \
#include \
#include \
int main()
{
std::clock_t startTime = clock();
std::ifstream inf("C:/Users/Batman/Desktop/test/test.txt");
typedef std::multimap Map;
Map map;
std::string line;
for (unsigned int i=1; std::getline(inf,line); ++i){
//load tokens into vector
std::istringstream buffer(line);
std::istream_iterator beg(buffer), end;
std::vector tokens(beg, end);
//get keys
for(auto& s: tokens)
//std::cout >>" second;
outputFile > a;
return 0;
}
进一步的想法是:在导入数据时,将管道划分的文件拆分为不同的文件,每个文件有一列。有了它,我就不必解析任何东西,而是可以单独读取每一列
编辑:使用递归拆分函数优化了第一个示例。对于100.000条记录,仍然>30秒。希望看到仍然缺少实际的find()函数
有什么想法吗?
谢谢通常你会得到在关键字段上排序的输入文件,然后你不需要把整个文件加载到内存中。我可以做第一步,但是这意味着我必须读写两次。你必须在C++中做吗?使用<代码> AWK 更容易做到C++,但谢谢指出。如果输入没有排序,则需要将文件加载到内存中。如果需要进行笛卡尔乘积,则使用多重贴图支持重复关键点。
#include \
#include \
#include \
#include \
#include \
#include \
#include \
std::vector &split(const std::string &s, char delim, std::vector &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector split(const std::string &s, char delim) {
std::vector elems;
split(s, delim, elems);
return elems;
}
std::string getSelectedRecords(std::string record, int position){
std::string values;
std::vector tokens = split(record, ' ');
//get position in vector
for(auto& s: tokens)
//pick last one or depending on number, not developed
values = s;
return values;
}
int main()
{
clock_t startTime = clock();
std::ifstream secondaryFile("C:/Users/Batman/Desktop/test/secondary.txt");
std::set secondarySet;
std::string record;
for (unsigned int i=1; std::getline(secondaryFile,record); ++i){
std::string keys = getSelectedRecords(record, 2);
std::string values = getSelectedRecords(record, 1);
secondarySet.insert(keys + ">>>" + values);
}
clock_t midTime = clock();
std::ifstream primaryFile("C:/Users/Batman/Desktop/test/primary.txt");
std::ofstream outputFile("C:/Users/Batman/Desktop/test/output.txt");
while (getline(primaryFile, record))
{
//rewrite find() function to go through set and find all keys (first part until >> ) and output values
std::string keys = getSelectedRecords(record, 2);
if (secondarySet.find(keys) != secondarySet.end())
outputFile > a;
return 0;
}
#include \
#include \
#include \
#include \
#include \
#include \
#include \
int main()
{
std::clock_t startTime = clock();
std::ifstream inf("C:/Users/Batman/Desktop/test/test.txt");
typedef std::multimap Map;
Map map;
std::string line;
for (unsigned int i=1; std::getline(inf,line); ++i){
//load tokens into vector
std::istringstream buffer(line);
std::istream_iterator beg(buffer), end;
std::vector tokens(beg, end);
//get keys
for(auto& s: tokens)
//std::cout >>" second;
outputFile > a;
return 0;
}