在C++ std::unordered_map key中,是否可以检查枚举是否设置了n个标志?

jtw3ybtb  于 2023-08-09  发布在  其他
关注(0)|答案(2)|浏览(111)

我正在设置一个unordered_map,其中的键是Direction的枚举,定义为:

enum Direction : uint16_t {
    North = 1 << 0,
    East = 1 << 2,
    South = 1 << 3,
    West = 1 << 4,
    None = 1 << 5,
};

字符串
目标是检查是否至少设置了这些标志中的2个,但最多设置了 *n个标志。
使用上面定义的枚举,我尝试创建一些unordered_map

std::unordered_map<Direction, std::vector<Tile*>>*      groundTiles;
    std::unordered_map<Direction, std::vector<Tile*>>*      northEastHillTiles;
    std::unordered_map<Direction, std::vector<Tile*>>*      southEastHillTiles;
    std::unordered_map<Direction, std::vector<Tile*>>*      platformTiles;
    std::unordered_map<Direction, std::vector<Tile*>>*      wallTiles;


我将它们初始化为

groundTiles = new std::unordered_map<Direction, std::vector<Tile*>>();
    groundTiles->insert_or_assign(Direction::None, std::vector<Tile*>());
    groundTiles->insert_or_assign(Direction::East, std::vector<Tile*>());
    groundTiles->insert_or_assign(Direction::West, std::vector<Tile*>());
    groundTiles->insert_or_assign((Direction)(Direction::East|Direction::West),std::vector<Tile*>());

and so on for the other sets


然而,当我尝试从地面(或任何其他设置)拉一个瓷砖时,我无法检查是否至少设置了方向::东和方向::西。我试过:

Tile* westAndEastCapped = southEastHillTiles->at((Direction)(Direction::West | Direction::East)).at(0);


但它似乎只是默认为Direction::East集。
我如何从一个unordered_map中选择一个图块,同时设置了East和West标志,而没有其他标志?

ar5n3qh5

ar5n3qh51#

这不是std::unordered_map::at()的工作方式。它只从无序Map中检索与传入参数 * 相等 * 的键的值。相等的意思是“完全”。就这些。没别的了。
此外,如果指定的键不存在,at()会抛出异常。
std::unordered_map只知道它的键是某种不透明的值。std::unordered_map不关心键的任何解释或含义,除了std::unordered_map对它的键的唯一要求是它有一个相等比较和它有一个散列函数。
enum符合这些要求。结束。仅仅因为这个特定的enum被解释为某种类型的位掩码,对std::unordered_map来说没有任何意义。
std::unordered_map不适合你试图访问它的值的方式,它不会工作。您可能需要为您的值设计一个自定义容器,以有效地实现所需的访问模式。
在最坏的情况下,你总是可以求助于范围迭代:

for (auto &[key, value]: southEastHillTiles)
{
  // ...
}

字符串
然后检查Map中的每个当前key,以确定它是否符合您正在搜索的内容。这是非常低效的,但这几乎是unordered_map唯一能做的事情。

dauxcl2d

dauxcl2d2#

无序Map被设计成非常有效地找到对应于一个特定键值的元素。不幸的是,在你的问题中,你不知道你要找的键值。您只知道密钥必须满足的一些约束。
一种方法是遍历所有现有的键并检查它们是否与约束匹配。但它不是很有效率。
如果这些消耗性的搜索很频繁,并且如果你的map中的key相对稳定,你可以考虑预先计算研究:搜索Map会将每个元素Direction与包含此方向的键**set相关联:

  • 不需要一个大的迭代来快速找到相关的几个键。有了这些键,你就可以进入你的完整Map,获得瓷砖。
  • 如果你正在寻找组合,你可以找到包含你正在寻找的每个方向的关键点集,并执行两组的intersection

考虑到你只有几个基本方向,你甚至可以预先计算每个可能组合的集合(因为方向东|西方不是很相关,组合学应该保持在控制之下)。
问题是,每一个新的关键字插入到你的瓷砖Map将需要重新计算搜索Map。但是你可以从源头上解决这个问题,并定义一个特殊的容器来提供所有这些功能:对于插入到该容器中的每个新的关键字和区块值,容器将更新用于查询的相关集合。
注意:如果你的Map非常动态,添加和删除了大量的键,或者键的数量可能会变得非常大,那么所提出的方法的效率增益可能会丢失。在这种情况下,您需要寻找不同的索引方案,例如**bitmap indexing**(或等效方案,例如某种trie-不是打字错误)。

相关问题