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

时间:2015-01-13 17:45:40

标签: c++ dictionary vector stl c++98

我有两个类:InitTable和InitEntry。 InitTable包含std::map table,其存储条目(汽车)的ID,以及代表该汽车的对象(InitEntry)。每个InitEntry都有3个成员变量:

  1. std::string ID
  2. double speed
  3. std::string heading
  4. 我的目标是首先将所有汽车存储在std::map table中,然后迭代该数据结构,并尝试根据公共属性将汽车组织成集群(std::vector<InitEntry>):{{ 1}}&amp; speed

    示例:

    假设我们有6辆车(ids 0到8)

    • car0:id:&#34; 0&#34;,速度:22,标题&#34; N&#34;
    • car1:id:&#34; 1&#34;,速度:26,标题&#34; N&#34;
    • car2:id:&#34; 2&#34;,速度:28,标题&#34; W&#34;
    • car3:id:&#34; 3&#34;,速度:12,标题&#34; E&#34;
    • car4:id:&#34; 4&#34;,速度:10,标题&#34; E&#34;
    • car5:id:&#34; 5&#34;,速度:45,标题&#34; S&#34;

    为了保持简单,在这个阶段对我来说仅仅根据航向对汽车进行分组就足够了。结果将是:

    heading

    不幸的是,我对C ++ STL知之甚少,无法理解如何在C ++中实现这一点。


    InitTable.h:

    std::vector clus1 = {car0, car1}
    std::vector clus2 = {car2}
    std::vector clus3 = {car3, car4}
    std::vector clus4 = {car5}
    

    InitTable.cc:

        #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;
        };
    

    InitEntry.h:

    #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.cc:

    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;
    
    };
    

    编辑1:添加额外描述(根据@TomaszLewowski的要求)。

    是的,我的目标是按标题组织车辆,然后根据速度进行组织。所以最初会有一个大的车辆集群在某个方向上运行,后来需要根据速度分成更多的集群。让我们说:车辆驶向&#34;北部&#34;,速度:0 - 20 ......速度:40 - 50 ......等等

2 个答案:

答案 0 :(得分:0)

考虑将std::map<std::string, InitEntry*> table;更改为:

std::vector<InitEntry> table;

然后,您需要将*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;
    }
}    

要对table进行排序,您需要决定要排序的内容。

  • 按ID排序: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.getHeading() < second.getHeading();});

显然你需要添加吸气剂来使这些工作。

答案 1 :(得分:0)

如果你不想迭代所有元素(我猜你不会),那么唯一的选择就是将这些组保留在某个地方,并且只有主表中的一些索引。这看起来大致如下:

#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;
};

按标题分组非常明显,因为它只需要一个简单的地图。但是,当涉及到速度变得有点困难时 - 你需要描述分组的要求(通过实现函数getSpeedGroupId),因为双精度不应该被用作地图索引。

如果您更喜欢更安全的内存管理方法,则可以Entry*替换std::shared_ptr<Entry>中的EntryProxyEntry替换std::shared_ptr<Entry> InitTable::entries }}。在这种情况下,您还需要将创建从Entry e{id, speed, heading更改为auto e = std::make_shared<Entry>(id, speed, heading)

如果删除对您来说过于复杂,您可以在列表中保留EntryProxy个结构,并在entries地图中引用特定的迭代器。

您可能也不喜欢群组为EntryProxy且单个元素为Entry这一事实 - 在这种情况下,您可能会getEntry也返回EntryProxy