简体   繁体   English

将std :: map的数据拆分为多个std :: vector

[英]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个成员变量:

  1. std::string ID
  2. double speed
  3. 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 ,然后遍历该数据结构,然后尝试基于常见属性( speedheading )将汽车组织到群集( std::vector<InitEntry> )中。

Example: 例:

Lets assume we have 6 cars (ids 0 to 8) 假设我们有6辆车(编号0到8)

  • car0: id: "0", speed: 22, heading "N" car0:id:“ 0”,速度:22,标题为“ N”
  • car1: id: "1", speed: 26, heading "N" car1:id:“ 1”,速度:26,标题为“ N”
  • car2: id: "2", speed: 28, heading "W" car2:id:“ 2”,速度:28,标题为“ W”
  • car3: id: "3", speed: 12, heading "E" car3:id:“ 3”,速度:12,标题为“ E”
  • car4: id: "4", speed: 10, heading "E" car4:id:“ 4”,速度:10,标题为“ E”
  • car5: id: "5", speed: 45, heading "S" car5:id:“ 5”,速度:45,标题为“ S”

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进行排序,您需要确定排序依据。

  • To sort by ID: std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getID() < second.getID();}); 按ID排序: std::sort(table.begin(), table.end(), [](const auto& first, const auto& second){return first.getID() < second.getID();});
  • To sort by speed: 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();});
  • To sort by heading: 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>EntryProxyEntrystd::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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM