[英]splitting data of a std::map into multiple std::vectors
I have two classes: InitTable and InitEntry. 我有两个类:InitTable和InitEntry。 InitTable contains a
std::map table
which stores the ID
of an entry (car), and on object ( InitEntry
) which represents that car. InitTable包含一个
std::map table
,该std::map table
存储条目(汽车)的ID
,以及代表该汽车的对象( InitEntry
)。 Every InitEntry
has 3 member variables: 每个
InitEntry
都有3个成员变量:
std::string ID
double speed
std::string heading
My goal is to first store all the cars in the std::map table
, and then iterate through that data structure, and try to organize the cars into clusters ( std::vector<InitEntry>
) based on common properties: speed
& heading
. 我的目标是首先将所有汽车存储在
std::map table
,然后遍历该数据结构,然后尝试基于常见属性( speed
和heading
)将汽车组织到群集( std::vector<InitEntry>
)中。
Example: 例:
Lets assume we have 6 cars (ids 0 to 8) 假设我们有6辆车(编号0到8)
To keep it simple, at this stage for me it would be enough to group the cars only based on heading. 为了简单起见,在我这个阶段,仅根据航向将汽车分组就足够了。 And the result would be:
结果将是:
std::vector clus1 = {car0, car1}
std::vector clus2 = {car2}
std::vector clus3 = {car3, car4}
std::vector clus4 = {car5}
Unfortunately, I do not have enough knowledge of C++ STL to be able to understand how to achieve this in C++. 不幸的是,我对C ++ STL的了解不足,无法理解如何在C ++中实现这一点。
InitTable.h: InitTable.h:
#include <InitEntry.h>
class InitTable {
public:
InitTable();
virtual ~InitTable();
void clearTable();
void addEntry(std::string ID, double speed, std::string heading);
void deleteEntry(std::string ID);
InitEntry* getEntry(std::string ID);
protected:
std::map<std::string, InitEntry*> table;
};
InitTable.cc: InitTable.cc:
#include"InitTable.h"
InitTable::InitTable(){}
InitTable::~InitTable()
{
clearTable();
}
void InitTable::clearTable()
{
this->table.clear();
}
void InitTable::addEntry(std::string ID, double speed, std::string heading)
{
InitEntry* newEntry = new InitEntry(ID, speed, heading);
std::cout<< "server::InitTable: vehicle registered to the init table" << newEntry << endl;
table.insert(std::make_pair(ID, newEntry));
}
void InitTable::deleteEntry(std::string ID)
{
InitEntry* ie = getEntry(ID);
if (ie != NULL)
{
table.erase(ID);
delete ie;
}
}
InitEntry* InitTable::getEntry(std::string ID)
{
std::map<std::string, InitEntry*>::iterator it = table.find(ID);
if (it != table.end())
{
return it->second;
}
else
{
std::cout << "such entry does not exist" << endl;
return NULL;
}
}
InitEntry.h: InitEntry.h:
class InitEntry {
public:
virtual ~InitEntry();
InitEntry(std::string ID, double speed, std::string heading);
std::string getID();
protected:
std::string sumoID;
double speed;
std::string heading;
};
InitEntry.cc: InitEntry.cc:
#include "InitEntry.h"
InitEntry::InitEntry(std::string ID, double speed, std::string heading): ID(ID), speed(speed), heading(heading){}
InitEntry::~InitEntry(){}
std::string InitEntry::getID()
{
return this->ID;
}
EDIT 1: adding extra description (by request of @TomaszLewowski). 编辑1:添加额外的说明(通过@TomaszLewowski的请求)。
Yes, my goal would be to organize the vehicles in clusters, by the heading, and then based on the speed. 是的,我的目标是按照标题将车辆分组,然后根据速度分组。 So initially there would be one big cluster of vehicles going on a certain direction, which later would need to be split into more clusters, based on speed.
因此,最初会有一个大的车辆集群沿某个方向行驶,后来需要根据速度将其分为更多的集群。 Lets say: vehicles heading "north", with speed: 0 - 20... with speed speed: 40 - 50...etc
假设:驶向“北方”的车辆,速度:0-20 ...,速度:40-50 ... etc
Consider changing your std::map<std::string, InitEntry*> table;
考虑更改您的
std::map<std::string, InitEntry*> table;
to: 至:
std::vector<InitEntry> table;
You would then need to change your *Entry
methods to: 然后,您需要将
*Entry
方法更改为:
void InitTable::addEntry(std::string ID, double speed, std::string heading)
{
table.push_back(InitEntry(ID, speed, heading));
std::cout<< "server::InitTable: vehicle registered to the init table" << table.back() << endl;
}
void InitTable::deleteEntry(std::string ID)
{
auto it = remove_if(table.begin(), table.end(), [&](const auto& i){return i.getID() == ID;});
table.resize(distance(table.begin(), it));
}
InitEntry* InitTable::getEntry(std::string ID)
{
auto it = find_if(table.begin(), table.end(), [&](const auto& i){return i.getID() == ID;});
if (it != table.end())
{
return it->second;
}
else
{
std::cout << "such entry does not exist" << endl;
return NULL;
}
}
To sort table
you would need to decide what to sort by. 要对
table
进行排序,您需要确定排序依据。
std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getID() < second.getID();});
std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getID() < second.getID();});
std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getSpeed() < second.getSpeed();});
std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getSpeed() < second.getSpeed();});
std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getHeading() < second.getHeading();});
std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getHeading() < second.getHeading();});
Obviously you'd need to add the getters to make these work. 显然,您需要添加吸气剂才能完成这些工作。
If you don't want to iterate over all elements (and I guess you don't), then only option is to keep these groups somewhere, and only some indices to them in the main table. 如果您不想遍历所有元素(我想您不是),那么唯一的选择就是将这些组保留在某个位置,并且在主表中仅保留一些指向它们的索引。 This would look roughly like that:
大致如下所示:
#include <string>
#include <vector>
#include <map>
#include <cassert>
#include <algorithm>
typedef std::string ID;
typedef std::string Heading;
typedef double Speed;
struct Entry
{
ID id;
Speed speed;
Heading heading;
};
class EntryProxy
{
public:
EntryProxy(Entry* target) : entry(target)
{}
ID getId()
{
return entry->id;
}
Speed getSpeed()
{
return entry->speed;
}
Heading getHeading()
{
return entry->heading;
}
private:
Entry* entry;
};
class InitTable
{
public:
const std::vector<EntryProxy>& getSameHeading(std::string id)
{
return groupedByHeadings.at(entries.at(id).heading);
}
const std::vector<EntryProxy>& getSimilarSpeed(std::string id)
{
return groupedBySpeed.at(calculateSpeedGroupIndex(entries.at(id).speed));
}
void addEntry(ID id, Speed speed, Heading heading)
{
Entry e{ id, speed, heading };
auto record = entries.insert(std::make_pair(id, e)); // pair<iterator, bool>
groupedByHeadings[record.first->second.heading].push_back(EntryProxy(&record.first->second));
groupedBySpeed[calculateSpeedGroupIndex(record.first->second.speed)].push_back(EntryProxy(&record.first->second));
}
void deleteEntry(ID id)
{
auto entry = entries.find(id);
assert(entry != entries.end());
auto currentEntryHeadings = groupedByHeadings[entry->second.heading];
currentEntryHeadings.erase(std::find_if(currentEntryHeadings.begin(), currentEntryHeadings.end(), [&entry](EntryProxy p){return p.getId() == entry->second.id; }));
auto currentEntrySpeeds = groupedBySpeed[calculateSpeedGroupIndex(entry->second.speed)];
currentEntrySpeeds.erase(std::find_if(currentEntrySpeeds.begin(), currentEntrySpeeds.end(), [&entry](EntryProxy p){return p.getId() == entry->second.id; }));
entries.erase(id);
}
EntryProxy getEntry(ID id)
{
return EntryProxy(&entries.at(id));
}
private:
typedef int SpeedGroupIndex;
SpeedGroupIndex calculateSpeedGroupIndex(Speed s)
{
// you may prefer a different implementation here
return s / 10;
}
std::map<ID, Entry> entries;
std::map<Heading, std::vector<EntryProxy> > groupedByHeadings;
std::map<SpeedGroupIndex, std::vector<EntryProxy> > groupedBySpeed;
};
Grouping by Heading is pretty obvious, as it requires only a simple map. 按标题分组很明显,因为它只需要一个简单的地图。 However, when it comes to speed it's a little tougher - you need to describe requirements for grouping (by implementing function
getSpeedGroupId
), as doubles shouldn't be used as map indices. 但是,在速度方面要困难一些-您需要描述分组的要求(通过实现
getSpeedGroupId
函数),因为不应将double用作地图索引。
In case you prefer a more safe approach towards memory management you can substitute Entry*
for std::shared_ptr<Entry>
in EntryProxy
and Entry
for std::shared_ptr<Entry>
in InitTable::entries
. 如果您愿意向内存管理更安全的方法可以替代
Entry*
为std::shared_ptr<Entry>
在EntryProxy
和Entry
的std::shared_ptr<Entry>
在InitTable::entries
。 In that case you would also need to change creation from Entry e{id, speed, heading
to auto e = std::make_shared<Entry>(id, speed, heading)
. 在这种情况下,您还需要将创建从
Entry e{id, speed, heading
更改为auto e = std::make_shared<Entry>(id, speed, heading)
。
If deleting is too complex for you, you may keep EntryProxy
structures in a list, and a reference to specific iterators in entries
map. 如果删除对您来说太复杂,则可以将
EntryProxy
结构保留在列表中,并在entries
映射中引用特定的迭代器。
You may also not like the fact that groups are EntryProxy
and single elements are Entry
- in such case you may make getEntry
also return EntryProxy
. 您可能还不喜欢组是
EntryProxy
而单个元素是Entry
的事实,在这种情况下,您可以使getEntry
也返回EntryProxy
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.