【问题标题】:A container that sorts and determines uniqueness from two different fields一个容器,从两个不同的字段中排序和确定唯一性
【发布时间】:2013-07-30 21:09:21
【问题描述】:

假设我已经定义了一个类型,比如

struct Item
{
    Item(int i, float j) : x(i), y(j) {}
    int x;
    float y;
};

我想将它们保存在一个容器中,使它们按Item::y 排序,并确保每个条目都有一个唯一的Item::x。我需要能够添加项目并删除顶部项目(即具有最小 y 值的项目)。

换句话说,可以做到这一点的东西:

Container<Item> my_container;
my_container.insert(Item(0, 3.2));
my_container.insert(Item(2, 1.1));
my_container.insert(Item(0, 0.2));
my_container.insert(Item(1, 0.6));
my_container.insert(Item(3, 0.6));
my_container.insert(Item(0, 6.1));

for (auto &i : my_container)
  std::cout << i.x << " " << i.y << std::endl;

理想情况下,这会产生:

1 0.6
3 0.6
2 1.1
0 6.1

起初我使用std::set&lt;Item&gt; 与确保item_1.y &lt; item_2.y 的比较功能,但这不允许在item_1.y == item_2.yitem_1.x != item_2.x 时添加项目。

有什么建议吗?谢谢。

更新

我决定研究 Boost Multi-Index,因为我有可用的 Boost。我几乎有一个解决方案(使用下面华金的回答):

#include <iostream>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>

using namespace boost::multi_index;

struct Item
{
    Item(int i, float j) : x(i), y(j) {}
    int x;
    float y;
};

typedef multi_index_container<
  Item,
  indexed_by<
    ordered_non_unique<member<Item,float,&Item::y> >,
    ordered_unique<member<Item,int,&Item::x> >
  >
> my_container_t;

int main()
{
  my_container_t mc;
  mc.insert(Item(0, 3.2));
  mc.insert(Item(2, 1.1));
  mc.insert(Item(0, 0.2));
  mc.insert(Item(1, 0.6));
  mc.insert(Item(3, 0.6));
  mc.insert(Item(0, 6.1));

  const my_container_t::nth_index<0>::type& y_index = mc.get<0>();
  // Print
  for (auto &i : y_index)
    std::cout << i.x << " " << i.y << std::endl;

  return 0;
}

这个程序的输出是:

1 0.6
3 0.6
2 1.1
0 3.2

这几乎是我想要的。请注意,插入 x = 0 的项目不会用该索引替换容器中的前一个项目。另外,顺便说一句,删除和返回容器中顶部项目的最佳方法是什么。像这样就足够了:

Item pop(my_container_t &mc)
{
  my_container_t::nth_index<0>::type& container = mc.get<0>();
  auto item = *container.begin();
  container.erase(container.begin());
  return item;
}

【问题讨论】:

  • 你的样本有 6 个输入和 4 个输出,令人困惑。
  • @MooingDuck 只有 4 个输出,因为带有 x=0 的项目被添加了 3 次。很像一个集合,这些项目中的最后两个不会添加到容器中,因为带有x=0 的项目已经在容器中。
  • 为什么插入Item(0, 4.7)没有覆盖Item(0, 3.2)
  • @MarkRansom 抱歉,这是个错误,我已经编辑了问题。
  • 假设他正在使用自己的自定义容器,他不能只是改变容器的插入功能的逻辑,以便它决定是否添加项目(基于x的值)和在容器中给它什么位置(基于 y 的值)?

标签: c++ map set containers


【解决方案1】:

您需要两个容器:一个确保x 的唯一性,另一个提供y 然后x 的排序。

boostmulti_index 容器可以同时完成这两项工作,但可能有点矫枉过正。

使用 x 中的 setunordered_set 值,并丢弃已经存在的东西。

有一个由y 排序的元素set,然后是xstd::tie(y,x)&lt;std::tie(o.y,o.x) 是最简单和最安全的 C++11 方式),或者一个由y 排序的multiset,以维持秩序。我自己更喜欢sets 而不是multisets,但这可能只是性格缺陷。

【讨论】:

    【解决方案2】:

    与其他人所说的相反,我不考虑使用 Boost.MultiIndex 矫枉过正:这正是 lib 设计的那种情况。

    using namespace boost::multi_index;
    
    typedef multi_index_container<
        Item,
        indexed_by<
            ordered_non_unique<member<Item,float,&Item::y> >,
            ordered_unique<member<Item,int,&Item::x> >
        >
    > my_container_t;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-22
      • 1970-01-01
      • 1970-01-01
      • 2014-10-28
      • 1970-01-01
      • 2012-08-01
      • 2010-12-10
      • 2019-01-31
      相关资源
      最近更新 更多