简体   繁体   English

标准::地图<tuple<int,int> .lower_bound/upper_bound 前缀搜索没有找到后缀的最小/最大元素

[英]std::map<tuple<int,int>.lower_bound/upper_bound prefix search without finding minimum/maximum elements for suffix

I am building a class which uses a std::map<tuple<...>> as a lookup data structure.我正在构建一个使用std::map<tuple<...>>作为查找数据结构的类。 I want to be able to do a prefix search on the map to find all elements sharing a certain prefix inside the tuple.我希望能够在地图上进行前缀搜索,以查找在元组内共享某个前缀的所有元素。 For instance:例如:

using namespace std;
map<tuple<int,int,int,string>,Value> index;
index.insert(make_tuple(1,1,1,"a"),Value());
index.insert(make_tuple(1,1,2,"b"),Value());
index.lower_bound(make_tuple(1,1,std::numeric_limits<int>::min(),""));

This does exactly what I need but I have to manually (for non POD types) figure out the minimum value.这正是我需要的,我必须手动(对于非 POD 类型)找出最小值。 Even worse, when I want to find the highest element with a certain prefix (which I do), I would have to find the maximum element value for a certain type, which in case of string is rather problematic.更糟糕的是,当我想找到具有特定前缀的最高元素(我这样做)时,我必须找到某种类型的最大元素值,这在string情况下是相当有问题的。

Ideally, I would be able to supply map.find/lower_bound/upper_bound (not std::find which is linear complexity on maps) with a separate comparison which does not take the suffix into account but unfortunately this is not possible, most likely because prefix search is more or less the only sensible application.理想情况下,我将能够提供map.find/lower_bound/upper_bound (不是 std::find,这是地图上的线性复杂性),并进行单独的比较,不考虑后缀,但不幸的是,这是不可能的,很可能是因为前缀搜索或多或少是唯一合理的应用程序。

I think options would be modifying the comparison used by map at runtime (which I consider extremely bad style) or implementing a numeric_limits equivalent for all types I will have inside of tuples.我认为选项将在运行时修改 map 使用的比较(我认为这是非常糟糕的风格)或为我将在元组中拥有的所有类型实现 numeric_limits 等价物。

Is there a better option out there for doing a prefix search on a map/set?在地图/集合上进行前缀搜索是否有更好的选择?

You get to pass in a "static" comparison functor to the map when you define it.在定义map时,您可以将“静态”比较函子传递给map The default ordering on tuple<...> is a lexicographic ordering on the type. tuple<...>的默认顺序是类型的字典顺序。

Extend the key type to ones that allow for fields to be flagged as max or min values, and provide a sorting algorithm that accepts them.将键类型扩展为允许将字段标记为maxmin的键类型,并提供接受它们的排序算法。

ie, something like this:即,像这样:

template<typename T>
struct InfiniteExtensionOf
{
  enum ExtendedOrder {NegInfinity=-1, Normal=0, PosInfinity=1};
  ExtendedOrder order;
  T value;
  bool operator<(InfiniteExtensionOf const& other) const
  {
    if (order != other.order)
      return order<other.order;
    return value < other.value;
  }
  template<typename U>
  InfiniteExtensionOf( U&& u ):order(Normal),value(std::forward(u)) {}
  InfiniteExtensionOf( InfiniteExtensionOf&& other ):order(other.order),value(std::move(other.value)) {}
  InfiniteExtensionOf( InfiniteExtensionOf& other ):order(other.order),value(other.value) {}
  InfiniteExtensionOf( InfiniteExtensionOf const& other ):order(other.order),value(other.value) {}
  InfiniteExtensionOf( ExtendedOrder& eo ):order(eo), value() {}
  InfiniteExtensionOf( ExtendedOrder&& eo ):order(eo), value() {}
  InfiniteExtensionOf( ExtendedOrder const& eo ):order(eo), value() {}
};

then key like this:然后像这样键:

map<tuple<InfiniteExtensionOf<int>, InfiniteExtensionOf<int>, InfiniteExtensionOf<int>, InfiniteExtensionOf<string>>, Value> myMap;

which should accept tuple s without the InfiniteExtensionOf argument (as such tuples implicitly convert, I hope), and you can specify +inf or -inf as the value of a particular field easily when calling lower_bound or upper_bound .它应该接受没有InfiniteExtensionOf参数的tuple s(因为这样的 tuple 隐式转换,我希望),并且您可以在调用lower_boundupper_bound时轻松指定 +inf 或 -inf 作为特定字段的值。

... ...

Note that if lower_bound took a template argument and only required it to be compatible to elements in the map in a way that agreed with the existing ordering, this would be less hassle.请注意,如果lower_bound接受一个模板参数,并且只要求它以与现有顺序一致的方式与地图中的元素兼容,这将减少麻烦。 :) But sadly, that isn't true. :) 但遗憾的是,事实并非如此。

What you could do is not using the key types directly but sort of a tristate version of an optional type:您可以做的不是直接使用键类型,而是使用可选类型的三态版本:

  1. If the value is set, the comparison just uses the value.如果设置了该值,则比较仅使用该值。
  2. If the small flag is set the value is thought to be smaller than all other values.如果设置了small标志,则认为该值小于所有其他值。
  3. If the large flag is set the value is thought of being larger than any other value.如果设置了large标志,则认为该值大于任何其他值。

To find the lower bound you would then search, eg, using the small value:要找到下限,您将进行搜索,例如,使用small值:

map.lower_bound(srd::make_tuple(
    tristate<int>(17),
    tristate<std::string>(tristate_small)));

This is for a map having a key made up of an int and a std::string , each one potentially replaced by a small or a large value.这是针对具有由intstd::string组成的键的映射,每个键都可能被一个小值或大值替换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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